- 两个脚本的 HTTP 请求改为 ProxyHandler({}) 强制绕过系统代理:
环境有 HTTP_PROXY/HTTPS_PROXY 时,urllib 会把 localhost 请求也丢给代理,
结果代理回 502,看起来像 OC 挂了其实是被劫走(本轮实测复现)
需要走代理时用 MCPCTL_USE_PROXY=1 / OCSKILL_USE_PROXY=1 显式开启
- ocskill 输入嗅探增强:未知后缀按魔数/内容识别 .b64、zip、markdown
- frontmatter 支持 YAML 块标量(description: > |),中文折行不补空格
- 新增子仓库自身 .gitignore(父仓库的 ignore 对子仓库无效,__pycache__ 曾被误提交)
- README 补充代理 502 与 401 随机密码的排查说明
149 lines
6.3 KiB
Markdown
149 lines
6.3 KiB
Markdown
# wsl-round-mcp — 本机 ⇄ WSL OpenCode 互通工具
|
||
|
||
打通**本机 OpenCode** 与 **WSL 里的 OpenCode**:skill 列表互查、skill 一键推送、MCP 配置对调开关。
|
||
全部零第三方依赖,只要装了 Python 3 就能跑。
|
||
|
||
---
|
||
|
||
## 一、双击就能用(小白版)
|
||
|
||
把整个 `wsl-round-mcp` 文件夹拷到任意位置,双击对应的 bat:
|
||
|
||
| 文件 | 作用 |
|
||
| --- | --- |
|
||
| `skill-list.bat` | 连接 WSL 的 OC,列出它当前有哪些 skill |
|
||
| `skill-push.bat` | 会让你粘贴一个 skill 路径(zip / 目录 / SKILL.md / base64),校验格式后写进 WSL 的 skill 目录 |
|
||
| `skill-pull.bat` | 会让你输入 skill 名,把它从 WSL 拷回本机 `skills-backup\` |
|
||
| `mcp-status.bat` | 查看 MCP 当前是开是关、第1行是什么模式 |
|
||
| `mcp-on.bat` | 把配置对调为「含 MCP」并热重载 |
|
||
| `mcp-off.bat` | 把配置对调为「安静版(无 MCP)」并热重载 |
|
||
|
||
> bat 内部会自动 `chcp 65001`,中文输出不会乱码。
|
||
> 没装 Python 或没加进 PATH,会提示 `Python not found in PATH`。
|
||
|
||
---
|
||
|
||
## 二、命令行用法
|
||
|
||
### 1. `ocskill.py` — skill 互通
|
||
|
||
```bash
|
||
# 列出 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 目录」):
|
||
|
||
1. **解码归一**:zip 就解压(带 zip-slip 目录穿越防护),目录原样用,
|
||
单个 `.md` 会包成目录,base64 字符串先解成文件再判断是 zip 还是 md。
|
||
2. **定位 `SKILL.md`**:允许压缩包里多套一层父目录(最深 3 层)。
|
||
3. **校验标准 skill 格式**,四项全过才算通过:
|
||
- 找得到 `SKILL.md`
|
||
- 文件以 `---` 开头,有 YAML frontmatter
|
||
- frontmatter 里有 `name`,且只含 `字母/数字/._-`
|
||
- frontmatter 里有 `description`(大模型靠它决定何时调用)
|
||
4. **写入** `\\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 的 `server.password`,先试 Bearer、401 再试 Basic |
|
||
|
||
### 2. `mcpctl.py` — MCP 配置对调开关
|
||
|
||
```bash
|
||
python mcpctl.py status # 看状态(只读)
|
||
python mcpctl.py on # 对调成含 MCP + 热重载
|
||
python mcpctl.py off # 对调成安静版 + 热重载
|
||
python mcpctl.py mode # 看第1行
|
||
python mcpctl.py mode 手动 # 改第1行(自动/手动/关闭,或 auto/manual/off)
|
||
python mcpctl.py status --target wsl # 操作 WSL 那一份配置
|
||
python mcpctl.py off --no-reload # 只对调文件,不调用重载
|
||
```
|
||
|
||
它读的正是 `mcpcfg.txt` 那三行:
|
||
|
||
```
|
||
自动 ← 第1行:模式
|
||
C:\...\opencode.json.1 ← 第2行:含 MCP 的原始配置
|
||
C:\...\opencode.json ← 第3行:删了 MCP 的安静配置
|
||
```
|
||
|
||
**状态判定只看活文件**(文件名为 `opencode.json` 的那份)里 `mcp.servers` 是否非空,
|
||
所以对调之后第2/3行的身份怎么漂移都不影响判断——这与 TUI 插件、server 插件完全一致。
|
||
|
||
模式语义(三个入口共用同一套规则):
|
||
|
||
| 模式 | `/mcpon` `/mcpoff` | 大模型(server 插件) | 本工具 `mcpctl.py` |
|
||
| --- | --- | --- | --- |
|
||
| 自动 | 可用(视为手动切换一次) | 可用 | 可用 |
|
||
| 手动 | **仅此可用** | 拒绝 | 可用(等价于用户输入命令) |
|
||
| 关闭 | 不注册 | 拒绝 | 拒绝(可用 `--ignore-mode` 强行) |
|
||
|
||
热重载打的是 `POST /api/location/reload`,会重建 location 并重读磁盘配置,MCP 立即生效;
|
||
失败时配置文件已经对调完成,重启 OC 一样生效。
|
||
|
||
---
|
||
|
||
## 三、连不上 OC 怎么办
|
||
|
||
**先看这一条(最常见):有 HTTP 代理时会假报 502。**
|
||
|
||
两个脚本已默认**绕过系统代理**直连(`ProxyHandler({})`)。
|
||
如果环境里有 `HTTP_PROXY` / `HTTPS_PROXY`,`urllib` 默认会把 `localhost` 请求也丢给代理,
|
||
结果是**代理回 502**,看起来像 OC 挂了、其实是被劫走了。
|
||
确实需要走代理时,设环境变量再运行:`MCPCTL_USE_PROXY=1` / `OCSKILL_USE_PROXY=1`。
|
||
|
||
其余排查:
|
||
|
||
1. 确认 WSL 里的 OC 起了:`opencode serve --port 4096`
|
||
2. 端口不对就加 `--port`,或设环境变量 `OC_PORT`
|
||
3. 提示 `401 WWW-Authenticate: Basic realm="Secure Area"` → OC 启用了服务密码。
|
||
用 `--password` 传值(默认自动从 `opencode.json` 的 `server.password` 读;
|
||
若该字段为空但 OC 仍要 401,说明它用了随机密码,需启动时设 `OPENCODE_SERVER_PASSWORD`)
|
||
4. `localhost` 不通 → 工具会自动 `wsl hostname -I` 取 WSL 真实 IP 再试
|
||
5. 全都失败 → `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`
|