内容
# WinReach MCP
[](https://github.com/GhouI/winreach-mcp/actions/workflows/ci.yml)
[](LICENSE)
[](https://modelcontextprotocol.io)
[](https://learn.microsoft.com/powershell/)
**为您的AI代理提供专属的Windows机器。** 远程PowerShell、文件传输、截图和完全的桌面控制(计算机使用 - 鼠标和键盘)通过HTTP - 使用每用户密钥、角色、命令策略、mTLS和审计日志进行保护。
WinReach是一个TypeScript [模型上下文协议](https://modelcontextprotocol.io)服务器,运行在Windows主机上,并通过Streamable HTTP将其公开给AI代理。大多数Windows MCP服务器在用户自己的机器上通过stdio本地运行,而 **WinReach是远程优先和安全的**:Codex、Claude Code和其他具有MCP能力的代理可以从任何地方运行PowerShell、移动文件、捕获屏幕和驱动鼠标和键盘 - 每个都有自己的持有者密钥、角色和命令策略,每次操作都写入审计日志,并且有一个命令即可发布的Cloudflare隧道,无需入站防火墙孔。
```text
代理或MCP客户端 -> WinReach MCP通过HTTP -> Windows (PowerShell + 桌面)
```
## 演示
[](assets/winreach-demo.mp4)
通过HTTP连接代理,运行远程PowerShell,驱动Windows桌面,并使用每个用户密钥在约30秒内保持所有操作。
▶ **[观看高质量MP4](assets/winreach-demo.mp4)** · 使用 [Remotion](https://www.remotion.dev/) 构建(源和重新渲染步骤在 [视频/](video/README.md) 中)。
还提供 **4:5 LinkedIn裁剪**,带有内置字幕 - [assets/winreach-linkedin.mp4](assets/winreach-linkedin.mp4)(封面:[assets/winreach-linkedin-cover.png](assets/winreach-linkedin-cover.png),字幕:[assets/winreach-linkedin.srt](assets/winreach-linkedin.srt))。
## 为什么选择WinReach?
大多数编码代理都习惯于终端,但Windows RDP是一个图形优先的环境。WinReach为代理提供了一个干净的命令界面:
- 从任何MCP客户端在Windows主机上运行PowerShell命令。
- 在变量、cwd或导入的模块重要的情况下保持持久的PowerShell会话。
- 使用内置的Cloudflare隧道将服务器发布给您的代理 - 无需固定的公共IP,无需入站防火墙孔。
- 使用持有者令牌身份验证和提供者防火墙,而不是暴露原始RDP工作流。
- 在连接真正的代理之前,使用诊断客户端进行本地测试。
- 避免IIS:WinReach是一个独立的Node HTTP服务器。
## 安装和连接(npx)
无需克隆,无需构建。WinReach作为npm包提供,带有`winreach-mcp`二进制文件。
**1. 生成令牌:**
```powershell
npx winreach-mcp gen-token
# -> 一个全新的随机持有者令牌,例如 9V4P3Am6EjKsMJVetyrl-s60NVcP_MmDvsP_gFgcq3U
```
**2a. 本地,零配置(stdio)- 最快路径。** 任何stdio MCP客户端都可以直接在Windows机器上启动WinReach。无需HTTP,无需隧道,无需令牌管理(如果不设置,则会创建一个短暂的管理令牌):
```jsonc
{
"mcpServers": {
"winreach": {
"command": "npx",
"args": ["-y", "winreach-mcp", "--stdio"]
}
}
}
```
**2b. 远程(HTTP + 持有者令牌)。** 在Windows主机上运行服务器,并通过网络连接代理(可选地通过内置的Cloudflare隧道):
```powershell
$env:WINREACH_TOKEN = "粘贴步骤1中的令牌"
npx winreach-mcp # 添加 --tunnel 以发布公共Cloudflare URL
```
用于 **Claude Code、Claude Desktop、Codex 和 Cursor** (本地stdio和远程HTTP表单)的复制粘贴代码段,以及Claude Desktop一键式扩展,位于 **[docs/CONNECT.md](docs/CONNECT.md)**。
`winreach-mcp` CLI:
| 命令 | 执行操作 |
| --- | --- |
| `npx winreach-mcp` (或 `start`) | 启动Streamable-HTTP MCP服务器(默认;添加 `--tunnel` 以获取公共URL)。 |
| `npx winreach-mcp --stdio` | 对于启动它的MCP客户端,通过本地stdio传输运行。 |
| `npx winreach-mcp gen-token` | 打印一个全新的随机持有者令牌。 |
## 工具
WinReach公开了多达八种MCP工具(最后三种是可选的):
| 工具 | 目的 |
| --- | --- |
| `powershell_execute` | 运行一个隔离的PowerShell命令。 |
| `powershell_open_session` | 启动一个持久的PowerShell会话。 |
| `powershell_send` | 向持久会话发送命令。 |
| `powershell_close_session` | 关闭持久会话。 |
| `powershell_list_sessions` | 列出活动会话。 |
| `take_screenshot` | 捕获Windows主机的当前屏幕图像。默认关闭(参见下文)。 |
| `computer_use` | 像人类一样控制桌面 - 移动/点击鼠标,输入文本,按键和滚动 - 通过Win32 `SendInput`。默认关闭;建议管理员/操作员角色(参见下文)。 |
| `file_upload` | 在配置的文件根目录内写入文件到主机。默认关闭(参见下文)。 |
| `file_download` | 读取文件从主机(可选移动)为base64。默认关闭(参见下文)。 |
命令结果包括:
```json
{
"commandId": "uuid",
"stdout": "hello\r\n",
"stderr": "",
"exitCode": 0,
"durationMs": 143,
"truncated": false
}
```
`take_screenshot` 捕获整个虚拟桌面(所有监视器)并返回一个MCP图像块(默认base64 PNG,可选`jpeg`)以及一个元数据块:
```json
{
"commandId": "uuid",
"success": true,
"format": "png",
"mimeType": "image/png",
"width": 1920,
"height": 1080,
"bytes": 82344,
"durationMs": 96
}
```
屏幕捕获需要一个活动的交互式桌面会话。如果WinReach在非交互式服务上下文(Windows会话0)中运行,则捕获失败,工具返回`success: false`以及PowerShell错误而不是图像。
由于屏幕捕获读取桌面上的内容,因此它是一种读取/流出功能,命令策略无法表达,因此 **默认禁用**。使用 `WINREACH_ALLOW_SCREENSHOT=1` 启用它,并可选地限制特定主体角色使用 `WINREACH_SCREENSHOT_ROLES`。当禁用(或当调用者的角色不允许)时,不会向该主体公开该工具。捕获写入 **服务器所有** 目录(`WINREACH_SCREENSHOT_DIR`)- 调用者无法选择路径 - 并在 `WINREACH_SCREENSHOT_RETENTION_HOURS` (默认 `8`)后自动删除,以便它们不会在主机上累积。
### 文件传输
`file_upload` 和 `file_download` 通过MCP(base64编码,SHA-256返回用于完整性)在代理和Windows主机之间移动文件。它们 **默认关闭**,并且仅在设置了沙箱根目录后才注册:
```powershell
$env:WINREACH_FILE_ROOT = "C:\winreach-files"
```
- **每个路径都相对于 `WINREACH_FILE_ROOT`。** 绝对路径,`..`遍历和符号链接都拒绝,因此传输永远不会触及根目录之外的文件。设置根目录就是启用这些工具。
- `file_upload` 拒绝覆盖除非 `overwrite: true`,并且根据需要创建根目录内的父目录。
- `file_download` 以base64返回文件;设置 `deleteSource: true` 以 **移动** 它(服务器副本在成功读取后删除)。
- 大于 `WINREACH_MAX_FILE_BYTES` (默认75 MB)的文件在任一方向上都被拒绝。
- 每次传输都写入审计日志(工具、主体、服务器路径、大小)。
## 快速入门
要求:
- Node.js 24或更新版本
- npm
- Windows PowerShell(`powershell.exe`)或PowerShell 7(`pwsh`)
在本地运行WinReach:
```powershell
git clone https://github.com/GhouI/winreach-mcp.git
cd winreach-mcp
npm install
$env:WINREACH_TOKEN = "dev-token"
npm run dev
```
服务器默认为:
```text
http://127.0.0.1:7573/mcp
```
使用另一个终端中的诊断客户端:
```powershell
$env:WINREACH_TOKEN = "dev-token"
npm run client -- list-tools
npm run client -- exec Write-Output hello
```
使用 `WINREACH_URLS` 目标多个WinReach服务器:
```powershell
$env:WINREACH_TOKEN = "shared-token"
$env:WINREACH_URLS = "http://win-1:7573/mcp,http://win-2:7573/mcp"
npm run client -- exec hostname
```
## 使用一个命令进行公共访问
当您在服务器上设置WinReach并希望代理从任何地方访问它时,请启用内置的 [Cloudflare快速隧道](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/do-more-with-tunnels/trycloudflare/)。WinReach在第一次使用时下载`cloudflared`,打开隧道,并打印一个可粘贴的代理配置。
```powershell
$env:WINREACH_TOKEN = "用长随机令牌替换"
$env:WINREACH_TUNNEL = "cloudflare"
npm run dev
```
输出:
```text
WinReach MCP 监听 http://127.0.0.1:7573/mcp
Cloudflare 隧道就绪:https://random-words.trycloudflare.com
公共MCP端点:https://random-words.trycloudflare.com/mcp
使用此公共端点连接代理(仍需要持有者令牌):
Claude Code:
claude mcp add --transport http winreach https://random-words.trycloudflare.com/mcp --header "Authorization: Bearer <WINREACH_TOKEN>"
...
```
您也可以使用标志临时启用它:
```powershell
npm run dev -- --tunnel
```
注意:
- `cloudflared` 通过环回连接到WinReach,因此隧道模式不需要 **没有** `0.0.0.0` 绑定和 **没有** 入站防火墙规则。WinReach告诉 `cloudflared` 重写转发的 `Host` 头为 `127.0.0.1`,以便服务器的内置DNS重新绑定保护继续工作。
- 隧道模式将远程命令服务器发布到公共互联网上,**仅**受持有者令牌保护。使用长随机 `WINREACH_TOKEN`(32+字符);如果令牌看起来很弱,WinReach会在启动时发出警告。
- 快速隧道主机名是随机的,**每次重启都会更改**。将打印的URL粘贴到您的代理中,或移动到 [命名Cloudflare隧道](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/) 以获取稳定的主机名。
- 持有者令牌在隧道上仍然被强制执行。将公共URL视为敏感信息,并在演示后旋转令牌。
- 自动安装通过HTTPS下载并运行官方`cloudflared`二进制文件。如果您需要已验证/固定的二进制文件,请设置 `WINREACH_TUNNEL_AUTOINSTALL=0`,并将 `WINREACH_CLOUDFLARED_PATH` 指向您已安装和检查的`cloudflared`。
## 连接代理
用于克劳德代码、克劳德桌面、Codex和Cursor(本地stdio和远程HTTP表单)的复制粘贴代码段以及一键式克劳德桌面扩展: **[docs/CONNECT.md](docs/CONNECT.md)**。
完整设置指南: [安装WinReach和连接代理](docs/INSTALL_AND_AGENT_USAGE.md)
功能概述: [WinReach功能](docs/FEATURES.md)
Codex `~/.codex/config.toml`:
```toml
[mcp_servers.winreach]
url = "http://WINDOWS_SERVER_IP:7573/mcp"
bearer_token_env_var = "WINREACH_TOKEN"
tool_timeout_sec = 120
default_tools_approval_mode = "prompt"
enabled = true
```
克劳德代码:
```powershell
claude mcp add --transport http winreach http://WINDOWS_SERVER_IP:7573/mcp `
--header "Authorization: Bearer YOUR_TOKEN"
```
另请参阅:
- [Codex配置示例](examples/codex-config.toml)
- [Claude Code MCP JSON示例](examples/claude.mcp.json)
## 远程Windows部署
在Windows主机上:
```powershell
git clone https://github.com/GhouI/winreach-mcp.git
cd winreach-mcp
npm install
$env:WINREACH_TOKEN = "用长随机令牌替换"
$env:WINREACH_HOST = "0.0.0.0"
$env:WINREACH_PORT = "7573"
npm run dev
```
打开Windows防火墙以允许MCP端口:
```powershell
New-NetFirewallRule `
-DisplayName "WinReach MCP 7573" `
-Direction Inbound `
-Protocol TCP `
-LocalPort 7573 `
-Action Allow
```
限制您的云防火墙,以便仅允许来自受信任IP地址的TCP `7573`访问。如果您只需要代理访问(而非原始端口访问),请首选 [隧道模式](#使用一个命令进行公共访问) 并将绑定保留在 `127.0.0.1`。
## 配置
首选UI? [`setup-web`](setup-web/)应用(Next.js)从表单生成环境变量、`start.ps1`、允许的IP地址的Windows防火墙规则和代理连接代码段 - 请参阅 [setup-web/README.md](setup-web/README.md)。
WinReach 读取 `WINREACH_*` 变量。
| 变量 | 默认值 | 描述 |
| --- | --- | --- |
| `WINREACH_TOKEN` | 需要* | 单个完全访问管理员的持有者令牌。*除非设置了 `WINREACH_PRINCIPALS`。 |
| `WINREACH_PRINCIPALS` | 空 | 每用户主体的JSON数组: `[{"name","role","token"\|"tokenEnv"\|"tokenHash","allow":[],"deny":[],"tools":[]}]`。启用每用户授权。一个键可以是纯文本(`token`/`tokenEnv`)或SHA-256十六进制 `tokenHash`(呈现的令牌通过SHA-256与之匹配 - 因此外部存储永远不需要纯文本)。 `tools`可选限制主体到特定工具名称(省略所有)。 |
| `WINREACH_COMMAND_ALLOWLIST` | 空 | 正则允许列表(逗号分隔或JSON数组)。如果非空,只有匹配的命令运行。 |
| `WINREACH_COMMAND_DENYLIST` | 空 | 正则拒绝列表(逗号分隔或JSON数组)。匹配的命令被阻止;拒绝优先于允许。 |
| `WINREACH_AUDIT_LOG` | 空 | 追加JSONL审计日志的路径。 |
| `WINREACH_TLS_CERT` | 空 | PEM证书路径。设置 `WINREACH_TLS_KEY` 以在应用中提供HTTPS。 |
| `WINREACH_TLS_KEY` | 空 | PEM私钥路径用于TLS。 |
| `WINREACH_TLS_KEY_PASSPHRASE` | 空 | 加密TLS密钥的密码短语。 |
| `WINREACH_TLS_CLIENT_CA` | 空 | PEM CA包,用于验证客户端证书。启用相互TLS(需要TLS)。 |
| `WINREACH_ALLOW_SCREENSHOT` | `0` | 设置为 `1` 以启用 `take_screenshot` 工具。默认禁用。 |
| `WINREACH_SCREENSHOT_ROLES` | 空 | 允许捕获的以逗号分隔的主体角色。空意味着任何经过身份验证的主体(启用时)。 |
| `WINREACH_SCREENSHOT_DIR` | 临时子目录 | 服务器拥有的目录捕获写入。调用者无法覆盖它。 |
| `WINREACH_SCREENSHOT_RETENTION_HOURS` | `8` | 旧捕获在此时间后删除(在启动和每次捕获之前)。设置为 `0` 以无限期保留。 |
| `WINREACH_ALLOW_COMPUTER_USE` | `0` | 设置为 `1` 以启用 `computer_use` 桌面输入工具。默认禁用。GUI控制绕过命令策略,因此仅授予受信任角色。 |
| `WINREACH_COMPUTER_USE_ROLES` | 空 | 允许驱动桌面的以逗号分隔的角色。空意味着任何经过身份验证的主体(启用时)。 |
| `WINREACH_COMPUTER_USE_MAX_ACTIONS_PER_SEC` | `10` | 每个主体的输入操作速率限制。 |
| `WINREACH_COMPUTER_USE_KEY_DENYLIST` | 空 | 阻止的按键和键的逗号分隔的正则表达式(例如 `win+r`)。一个速度限制,而不是边界。 |
| `WINREACH_COMPUTER_USE_HALT_FILE` | 空 | 如果存在此文件,则拒绝所有 `computer_use` 操作 - 操作员终止开关。 |
| `WINREACH_COMPUTER_USE_AUDIT_TEXT` | `0` | 设置为 `1` 以在审计日志中记录原始输入文本。默认关闭(仅长度 + 截断哈希)。 |
| `WINREACH_FILE_ROOT` | 空 | `file_upload`/`file_download` 的沙箱根目录。设置它即可启用这些工具;所有传输路径都在其中解析。 |
| `WINREACH_MAX_FILE_BYTES` | `78643200` | 每次传输的文件最大字节数(双向)。默认 75 MB。 |
| `WINREACH_URL` | `http://127.0.0.1:7573/mcp` | 单个WinReach服务器的诊断客户端URL。 |
| `WINREACH_URLS` | 空 | 使用 `WINREACH_TOKEN` 的多个服务器的诊断客户端以逗号分隔的URL。 |
| `WINREACH_TARGETS` | 空 | 命名服务器和每个目标的令牌环境变量的诊断客户端JSON数组。 |
| `WINREACH_HOST` | `127.0.0.1` | 绑定主机。除防火墙或隧道后,请仅使用 `0.0.0.0`。 |
| `WINREACH_PORT` | `7573` | 绑定端口。 |
| `WINREACH_ENDPOINT_PATH` | `/mcp` | MCP端点路径。 |
| `WINREACH_ALLOWED_ORIGINS` | 空 | 允许的 `Origin` 值的逗号分隔列表。 |
| `WINREACH_SHELL_PATH` | 自动 | 显式 `pwsh` 或 `powershell.exe` 路径。 |
| `WINREACH_CWD` | 进程工作目录 | 默认工作目录。 |
| `WINREACH_TIMEOUT_MS` | `30000` | 默认命令超时。 |
| `WINREACH_MAX_OUTPUT_BYTES` | `1048576` | 每个输出流的最大捕获字节数。 |
| `WINREACH_TUNNEL` | 空 | 设置为 `cloudflare` 以通过Cloudflare快速隧道发布服务器。 |
| `WINREACH_TUNNEL_AUTOINSTALL` | `1` | 丢失时自动下载 `cloudflared`。设置为 `0` 以要求预安装的二进制文件。 |
| `WINREACH_CLOUDFLARED_PATH` | 自动 | `cloudflared` 二进制文件的显式路径。 |
## 安全
WinReach是一个远程命令执行服务器。请像对待敏感基础设施一样对待它。
- 使用长随机 `WINREACH_TOKEN`。
- 保持 `WINREACH_HOST=127.0.0.1` 除非您有受信任的网络路径或使用隧道模式。
- 不要在原始端口上将WinReach直接暴露给公共互联网。
- 在您的提供商防火墙上限制TCP `7573`。
- 隧道URL仍然受到持有者令牌的保护,但请像对待机密一样对待它们,并在演示后旋转。
- 在可能的情况下,以专用低权限Windows用户身份运行。
- 在演示、测试会话和共享访问后轮换令牌。
### 硬化
WinReach现在可以通过外部代理强制执行传输安全、每客户端授权、命令策略和审计。
**在应用中提供HTTPS(可选使用相互TLS):**
```powershell
$env:WINREACH_TOKEN = "用长随机令牌替换"
$env:WINREACH_TLS_CERT = "C:\certs\winreach-cert.pem"
$env:WINREACH_TLS_KEY = "C:\certs\winreach-key.pem"
# 需要客户端证书(mTLS):连接没有由此CA签发的证书的客户端
# 将在TLS握手期间被丢弃,在持有者令牌检查之前。
$env:WINREACH_TLS_CLIENT_CA = "C:\certs\client-ca.pem"
npm run dev
```
**为每个客户端提供自己的身份、角色和命令策略:
```powershell
$env:WINREACH_PRINCIPALS = @'
[
{ "name": "ci", "role": "admin", "tokenEnv": "CI_TOKEN" },
{ "name": "agent", "role": "readonly", "tokenEnv": "AGENT_TOKEN",
"allow": ["^Get-", "^Test-"], "deny": ["Remove-Item", "Stop-Service"],
"tools": ["powershell_execute"] }
]
'@
```
**应用部署范围的防护和记录所有内容:
```powershell
$env:WINREACH_COMMAND_DENYLIST = "Remove-Item -Recurse,Format-Volume,Stop-Computer"
$env:WINREACH_AUDIT_LOG = "C:\logs\winreach-audit.jsonl"
```
全局策略和调用者的主体策略都必须允许命令;拒绝始终优先,非空允许列表阻止它不匹配的任何内容。被阻止的调用返回MCP错误并写入审计日志。
**以专用帐户安装为Windows服务:
```powershell
npm run build
$pw = Read-Host -AsSecureString "服务帐户密码"
./scripts/install-service.ps1 -EnvFile .env -ServiceAccount ".\winreach" -ServiceAccountPassword $pw
# 稍后使用以下命令删除:./scripts/uninstall-service.ps1
```
参见 [SECURITY.md](SECURITY.md) 获取完整的控制矩阵和超出范围的内容。
## 路线图
已发布:应用内HTTPS/mTLS,每个客户端授权,命令允许/拒绝策略,审计日志和Windows服务安装程序(参见 [强化](#强化))。
仍在计划中:
- 用于稳定主机名的命名Cloudflare隧道
- 请求级别的Windows集成身份验证(协商/NTLM)
- 速率限制和每个主体的配额
- Git Bash支持
- 打包发布
## 贡献
欢迎提出问题、建议和拉取请求。从 [CONTRIBUTING.md](CONTRIBUTING.md) 开始。
## 许可证
MIT。参见 [LICENSE](LICENSE)。
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器