内容
# mcp-oauth2-proxy
[](https://www.npmjs.com/package/mcp-oauth2-proxy)
[](https://nodejs.org/)
[](./LICENSE)
> 一个本地的 **stdio MCP 服务器**,它代理到一个远程的、**OAuth2 保护的 HTTP MCP 服务器**。将其放入 Claude Desktop、Cursor、VS Code Copilot 或任何其他 MCP 客户端中 - 只需在浏览器中登录一次即可。
```
MCP 客户端 ─stdio (JSON-RPC)─▶ mcp-oauth2-proxy ─HTTP+SSE + Bearer─▶ 上游 MCP 服务器
│
└─ OAuth2 token 端点 (IdP)
```
## 文档
本 README 是一个快速入门指南。**完整文档位于 [wiki](https://github.com/ChengleiYuan/mcp-oauth2-proxy/wiki)**。
| 页面 | 内容 |
| ---- | ------------ |
| [快速入门](https://github.com/ChengleiYuan/mcp-oauth2-proxy/wiki/快速入门) | 安装、首次运行、连接到客户端。 |
| [配置](https://github.com/ChengleiYuan/mcp-oauth2-proxy/wiki/配置) | 每个字段和环境变量。 |
| [OAuth2 授权和令牌](https://github.com/ChengleiYuan/mcp-oauth2-proxy/wiki/OAuth2-授权和令牌) | 授权流程、交互式登录、令牌 + 缓存生命周期。 |
| [发现](https://github.com/ChengleiYuan/mcp-oauth2-proxy/wiki/发现) | RFC 9728 / RFC 8414 端点发现。 |
| [安全](https://github.com/ChengleiYuan/mcp-oauth2-proxy/wiki/安全) | 威胁模型和内置防御。 |
| [远程主机(SSH 端口转发)](https://github.com/ChengleiYuan/mcp-oauth2-proxy/wiki/远程主机(SSH-端口转发)) | 在代理运行时登录。 |
| [故障排除](https://github.com/ChengleiYuan/mcp-oauth2-proxy/wiki/故障排除) | 常见问题和 FAQ。 |
| [架构](https://github.com/ChengleiYuan/mcp-oauth2-proxy/wiki/架构) · [桥接](https://github.com/ChengleiYuan/mcp-oauth2-proxy/wiki/桥接内部) · [OAuth2](https://github.com/ChengleiYuan/mcp-oauth2-proxy/wiki/OAuth2-内部) 内部实现 | 工作原理。 |
| [贡献和发布](https://github.com/ChengleiYuan/mcp-oauth2-proxy/wiki/贡献和发布) | 开发设置、测试、发布流程。 |
## 目录
- [功能](#功能)
- [工作原理](#工作原理)
- [需求](#需求)
- [安装](#安装)
- [快速入门](#快速入门)
- [连接到 MCP 客户端](#连接到MCP客户端)
- [配置](#配置)
- [安全](#安全)
- [开发](#开发)
- [超出范围](#超出范围)
- [许可证](#许可证)
## 功能
- **交互式 `authorization_code` + PKCE** 流程,带有内置的本地浏览器回调监听器 - 无需手动复制/粘贴代码。
- **刷新令牌缓存** 存储在磁盘上(AES-256-GCM,`0600`),因此浏览器每次在每台机器上只打开一次。
- **`client_credentials`** 授权,适用于无头/服务到服务的用法。
- **RFC 9728 + RFC 8414 发现**,从上游发现令牌和授权端点 - 通常需要零个 OAuth 配置。
- **主动令牌刷新**,带有偏差、飞行中去重和 401 → 使无效 → 重试循环。
- **可流式 HTTP** 上游支持:单次 JSON、SSE `text/event-stream` 响应和可选的长寿命服务器通知通道。遵循 `Mcp-Session-Id`。
- **仅 stderr 日志** (pino),带有令牌、机密和 `Authorization` 头的删除 - stdout 保持干净的 JSON-RPC 通道。
## 工作原理
1. **发现。** 可选地获取 RFC 9728/8414 元数据以填充 `tokenUrl`、`authorizationUrl` 和 `scope`。
2. **令牌管理器。** 用缓存、刷新偏差、飞行中去重和 401 使无效包装配置的 `Grant`。
3. **预取。** 在启动时调用 `getToken()` 一次,以便在第一个 MCP 消息到达之前发生交互式浏览器流程(如果需要)。
4. **桥接。** 对于每个 stdin JSON-RPC 行,POST 到 `upstream.url`,带有 `Bearer` 令牌;单次 JSON 响应变为一行 stdout,SSE 响应变为每事件一行。一个 `401` 触发 `invalidate()` 和一个重试。
5. **服务器流。** 在 `initialize` 后,可选地保持打开一个 `GET text/event-stream` 通道,用于服务器发起的通知。
有关完整的内部实现,请参阅 [架构](https://github.com/ChengleiYuan/mcp-oauth2-proxy/wiki/架构)、[桥接内部](https://github.com/ChengleiYuan/mcp-oauth2-proxy/wiki/桥接内部)和 [OAuth2 内部](https://github.com/ChengleiYuan/mcp-oauth2-proxy/wiki/OAuth2-内部) wiki 页面。
## 需求
- Node.js **20+**
- 一个受 OAuth2 保护的 MCP 服务器,使用 [Streamable HTTP MCP 传输协议](https://modelcontextprotocol.io/)。
- 一个与您的 IdP 注册的 OAuth2 客户端。对于交互式流程,请注册 `http://127.0.0.1:53682/callback` 作为重定向 URI(或您设置的 `OAUTH2_CALLBACK_PORT`)。
## 安装
您不需要安装任何内容 - MCP 客户端可以直接通过 `npx` 启动代理:
```sh
npx -y mcp-oauth2-proxy
```
对于本地代码库开发:
```sh
git clone https://github.com/ChengleiYuan/mcp-oauth2-proxy.git
cd mcp-oauth2-proxy
npm install
npm run build
```
## 快速入门
### 交互式登录(推荐用于最终用户)
```sh
UPSTREAM_URL=https://mcp.example.com/mcp \
OAUTH2_GRANT=authorization_code \
OAUTH2_CLIENT_ID=<您的客户端 ID> \
npx -y mcp-oauth2-proxy
```
在首次启动时,代理会发现 OAuth 端点,打开您的浏览器进行 PKCE 登录,在 `http://127.0.0.1:53682/callback` 捕获代码,将刷新令牌(加密)缓存在您的操作系统配置目录下,并启动桥接。后续启动将静默重用缓存的令牌。详情:[OAuth2 授权和令牌](https://github.com/ChengleiYuan/mcp-oauth2-proxy/wiki/OAuth2-授权和令牌)。
### 无头 / 服务帐户
```sh
UPSTREAM_URL=https://mcp.example.com/mcp \
OAUTH2_GRANT=client_credentials \
OAUTH2_TOKEN_URL=https://idp.example.com/oauth2/token \
OAUTH2_CLIENT_ID=my-service \
OAUTH2_CLIENT_SECRET='…' \
OAUTH2_SCOPE='mcp:read mcp:write' \
npx -y mcp-oauth2-proxy
```
## 连接到 MCP 客户端
```jsonc
{
"mcpServers": {
"remote-oauth2-mcp": {
"command": "npx",
"args": ["-y", "mcp-oauth2-proxy"],
"env": {
"UPSTREAM_URL": "https://mcp.example.com/mcp",
"OAUTH2_GRANT": "authorization_code",
"OAUTH2_CLIENT_ID": "<您的客户端 ID>"
}
}
}
}
```
在不支持解析 `.cmd` shims 的 Windows 主机上(因此 `command: "npx"` 无法启动),请使用显式表单:
```jsonc
{
"command": "cmd",
"args": ["/c", "npx", "-y", "mcp-oauth2-proxy"]
}
```
`env` 块中的路径必须是绝对路径,并且在所有平台上都使用正斜杠。
## 配置
代理可以通过 JSON 文件 (`MCP_PROXY_CONFIG`)、环境变量或两者的混合进行配置 - 环境变量覆盖文件值,然后合并结果将被验证。最小示例文件:
```jsonc
{
"upstream": { "url": "https://mcp.example.com/mcp" },
"oauth2": {
"grant": "authorization_code",
"clientId": "my-client",
"scope": "mcp:read mcp:write"
}
}
```
请参阅 [`config.example.json`](./config.example.json) 以获取更完整的示例。
最常用的环境变量:
| 环境变量 | 映射到 |
| --------------------- | ------------------- |
| `UPSTREAM_URL` | `upstream.url` |
| `OAUTH2_GRANT` | `oauth2.grant` |
| `OAUTH2_CLIENT_ID` | `oauth2.clientId` |
| `OAUTH2_CLIENT_SECRET`| `oauth2.clientSecret` |
| `OAUTH2_TOKEN_URL` | `oauth2.tokenUrl` |
| `OAUTH2_SCOPE` | `oauth2.scope` |
| `LOG_LEVEL` | `log.level` |
> **完整参考:** 每个字段、默认值和环境变量都在 [配置](https://github.com/ChengleiYuan/mcp-oauth2-proxy/wiki/配置) wiki 页面中记录。端点自动发现涵盖在 [发现](https://github.com/ChengleiYuan/mcp-oauth2-proxy/wiki/发现) 中。如果在远程机器上运行代理?请参见 [远程主机(SSH 端口转发)](https://github.com/ChengleiYuan/mcp-oauth2-proxy/wiki/远程主机(SSH-端口转发))。遇到问题?请参见 [故障排除](https://github.com/ChengleiYuan/mcp-oauth2-proxy/wiki/故障排除)。
## 安全
- 令牌由代理本身获取;上游 `Authorization` 头始终由代理设置,从不从客户端传递。
- 访问令牌仅存在于内存中。刷新令牌缓存在磁盘上(加密,AES-256-GCM,密钥文件模式 `0600`)- 诚实的混淆对抗偶然的磁盘读取,**不** 保护针对与同一 OS 用户运行的进程。
- 清晰的 `http://` 到非回环主机的请求在启动时被**拒绝**(使用 `ALLOW_INSECURE_HTTP=true` 覆盖);`https://` 和回环 `http://` 始终被允许。交互式回调监听器验证 `Host` 头以击败 DNS 重新绑定。
- 所有日志都输出到 stderr,令牌、机密和 `Authorization` 头被删除;stdout 保留为 JSON-RPC 通道。
完整的威胁模型和防御措施:[安全](https://github.com/ChengleiYuan/mcp-oauth2-proxy/wiki/安全)。
## 开发
```sh
npm install
npm run build # 编译 TS 到 dist/
npm run dev # tsx 监视
npm test # vitest(单元测试 + 集成测试)
```
集成测试启动了一个模拟的 OAuth2 令牌端点和一个模拟的 MCP 上游进程,并通过 `PassThrough` 流驱动真正的桥接 - 无需网络。项目布局、完整的测试策略和自动发布流程在 [贡献和发布](https://github.com/ChengleiYuan/mcp-oauth2-proxy/wiki/贡献和发布) 中有文档记录。
## 超出范围
- 每个进程的多个上游 MCP 服务器
- OS 密钥链支持的刷新令牌存储(DPAPI / 密钥链 / libsecret)
- mTLS / JWT 承载者 / 设备代码 / ROPC 授权
- HTTP / SSE 入站传输(这是 stdio MCP 服务器)
## 许可证
[MIT](./LICENSE)