Skip to main content
Glama
jfdjaf

mcp-model-proxy

by jfdjaf
README.md
# mcp-model-proxy

![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)
![Node: >=18](https://img.shields.io/badge/Node-%3E%3D18-green.svg)

一个最小的本地 MCP Server,把任意兼容 Claude Messages API 的上游包装成统一的 MCP 工具 `ask_model`。

> **注意**:本项目转发的是 Claude Messages API 格式的请求。其他服务(如 OpenAI、Gemini 原生 API)与此格式不兼容,直接填入不会生效。部分中转服务或网关会把 Claude Messages API 格式转发给 GPT/Gemini,这类服务可以用,但兼容性由中转服务保证,与本项目无关。

不负责账号管理、provider 切换或流式输出。就一件事:把上游接口变成 MCP 工具,让 MCP Inspector、编辑器插件或其他支持 MCP 的客户端能直接调用。

> **运行模式**:本项目使用 stdio 传输,必须由宿主客户端以子进程方式启动(即在 MCP 配置里指定 `command` 和 `args`)。直接运行 `node server.mjs` 不会监听任何端口,进程会挂起等待 stdin 输入,这是正常行为。

## 目录

- [系统要求](#system-requirements)
- [快速开始](#quick-start)
- [项目结构](#project-structure)
- [核心调用流程](#core-call-flow)
- [工作原理](#how-it-works)
- [MCP 工具说明](#mcp-tool)
- [接入常见 MCP 客户端](#mcp-clients)
- [验证方式](#verification)
- [故障排查](#troubleshooting)
- [已知限制](#known-limitations)
- [适用场景](#use-cases)
- [FAQ](#faq)
- [安全建议](#security)

<a id="system-requirements"></a>
## 系统要求

- Node.js 18+
- npm 7+
- 可访问兼容 Claude Messages API 的上游服务的网络环境(Node.js 默认不走系统代理,如需代理请设置 `HTTPS_PROXY` 环境变量)

依赖包:

- `@modelcontextprotocol/sdk`
- `zod`

<a id="quick-start"></a>
## 快速开始

### 1. 安装依赖

```bash
npm install
```

### 2. 设置环境变量

Windows PowerShell:

```powershell
$env:CLAUDE_MCP_BASE_URL = "https://your-base-url"
$env:CLAUDE_MCP_API_KEY = "your-token"
$env:CLAUDE_MCP_MODEL = "claude-sonnet-4-5"
$env:CLAUDE_MCP_ANTHROPIC_VERSION = "2023-06-01"
$env:CLAUDE_MCP_TIMEOUT_MS = "60000"
```

其中 `CLAUDE_MCP_ANTHROPIC_VERSION` 和 `CLAUDE_MCP_TIMEOUT_MS` 是可选项。参考 `.env.example` 维护自己的本地模板,不要把真实 token 提交到仓库。

### 3. 用 Inspector 测试

以下命令为 PowerShell 格式(Windows),macOS/Linux 请将行末的 `` ` `` 换成 `\`:

```powershell
npx @modelcontextprotocol/inspector --cli `
  node /path/to/mcp-model-proxy/server.mjs `
  --method tools/call `
  --tool-name ask_model `
  --tool-arg "prompt=介绍一下你自己"
```

### 4. 预期结果

```json
// 示意,非真实数据,实际 token 数取决于模型和 prompt
{
  "model": "claude-sonnet-4-5",
  "stop_reason": "end_turn",
  "usage": {
    "input_tokens": 100,
    "output_tokens": 76
  },
  "text": "..."
}
```

<a id="project-structure"></a>
## 项目结构

```text
mcp-model-proxy/
├─ examples/
│  ├─ assets/
│  │  ├─ core-call-flow.drawio
│  │  └─ core-call-flow.svg
│  ├─ mcp-client-config.windows.json
│  ├─ mcp-client-config.macos.json
│  └─ inspector-powershell.md
├─ .env.example
├─ .gitignore
├─ CHANGELOG.md
├─ LICENSE
├─ package.json
├─ package-lock.json
├─ server.mjs
└─ README.md
```

其中:

- `server.mjs` 是 MCP Server 主入口
- `examples/mcp-client-config.*.json` 是不同平台的宿主客户端配置示例
- `examples/assets/` 放 README 用到的流程图源文件和导出图

<a id="core-call-flow"></a>
## 核心调用流程

![mcp-model-proxy 核心调用流程](./examples/assets/core-call-flow.svg)

可编辑源文件见 `./examples/assets/core-call-flow.drawio`,后续如果要改节点文案、配色或布局,可以直接用 draw.io 或 `next-ai-draw-io` 打开继续调整。

<a id="how-it-works"></a>
## 工作原理

### 环境变量

| 变量 | 必填 | 说明 |
|------|------|------|
| `CLAUDE_MCP_BASE_URL` | 是 | Claude 兼容上游地址 |
| `CLAUDE_MCP_API_KEY` | 是 | 上游 API Key |
| `CLAUDE_MCP_MODEL` | 否 | 默认模型,默认 `claude-sonnet-4-5` |
| `CLAUDE_MCP_ANTHROPIC_VERSION` | 否 | 默认 `2023-06-01` |
| `CLAUDE_MCP_TIMEOUT_MS` | 否 | 上游请求超时,默认 `60000`,最小 `1000` |

### URL 自动补全

以下三种写法均可:

```text
https://example.com
https://example.com/v1
https://example.com/v1/messages
```

### 请求头

```text
x-api-key: <your-key>
anthropic-version: 2023-06-01
content-type: application/json
```

### 返回结构

```json
{
  "model": "claude-sonnet-4-5-20250929",
  "stop_reason": "end_turn",
  "usage": { "input_tokens": 100, "output_tokens": 76 },
  "text": "模型返回的正文"
}
```

<a id="mcp-tool"></a>
## MCP 工具说明

当前只暴露一个工具:`ask_model`

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `prompt` | string | 是 | 用户输入 |
| `system` | string | 否 | 系统提示词 |
| `model` | string | 否 | 覆盖默认模型 |
| `maxTokens` | number | 否 | 最大输出 token,默认 1024,上限 65536 |

补充说明:

- 传入超过 `65536` 的 `maxTokens` 不会发到上游,而会在本地参数校验阶段直接报错
- 真实可用的输出上限仍然取决于你的上游服务和模型本身

调用示例(`maxTokens` 不传时默认 1024,此处显式设为 512 以演示用法):

```json
{
  "prompt": "介绍一下你自己",
  "model": "claude-sonnet-4-5",
  "maxTokens": 512
}
```

使用 `system` 限定模型行为:

```json
{
  "prompt": "What is MCP?",
  "system": "You are a concise technical assistant. Reply in English only.",
  "maxTokens": 256
}
```

<a id="mcp-clients"></a>
## 接入常见 MCP 客户端

这类客户端的接入思路都差不多:

1. 指定启动命令为 `node /path/to/mcp-model-proxy/server.mjs`
2. 通过环境变量传入上游地址、API Key 和默认模型
3. 在客户端工具列表里调用 `ask_model`

下面以 Claude Code 这类支持 JSON MCP 配置的客户端为例(Windows,使用 `cmd /c` 启动;macOS/Linux 见 `examples/mcp-client-config.macos.json`):

> Windows 上部分 MCP 宿主(如 Claude Code)需要通过 `cmd /c` 间接调用 `node`,否则会出现路径解析失败。macOS/Linux 直接用 `"command": "node"` 即可。

```json
{
  "mcpServers": {
    "mcp-model-proxy": {
      "command": "cmd",
      "args": [
        "/c",
        "node",
        "/path/to/mcp-model-proxy/server.mjs"
      ],
      "env": {
        "CLAUDE_MCP_BASE_URL": "https://your-base-url",
        "CLAUDE_MCP_API_KEY": "your-token",
        "CLAUDE_MCP_MODEL": "claude-sonnet-4-5",
        "CLAUDE_MCP_ANTHROPIC_VERSION": "2023-06-01",
        "CLAUDE_MCP_TIMEOUT_MS": "60000"
      }
    }
  }
}
```

完整示例见 `examples/mcp-client-config.windows.json`。  
如果你使用的是其他支持 MCP 的宿主,按同样思路把命令、参数和环境变量填进去即可。

<a id="verification"></a>
## 验证方式

建议按顺序分层验证,不要直接看界面。

### 验证 1:直接打上游

以下为 Windows PowerShell 写法(`curl.exe` 避免 PowerShell 别名问题);macOS/Linux 将 `curl.exe` 改为 `curl`,行末反引号 `` ` `` 改为 `\`:

```powershell
curl.exe -sS -D - -X POST "https://your-base-url/v1/messages" `
  -H "x-api-key: your-token" `
  -H "anthropic-version: 2023-06-01" `
  -H "content-type: application/json" `
  --data-raw "{\"model\":\"claude-sonnet-4-5\",\"max_tokens\":64,\"messages\":[{\"role\":\"user\",\"content\":\"请只回复OK\"}]}"
```
```

### 验证 2:用 Inspector 调 MCP

```powershell
npx @modelcontextprotocol/inspector --cli `
  node /path/to/mcp-model-proxy/server.mjs `
  --method tools/call `
  --tool-name ask_model `
  --tool-arg "prompt=介绍一下你自己"
```

<a id="troubleshooting"></a>
## 故障排查

### `401 无效的令牌`

先分清楚是哪里报的:

- 上游直连就 `401`:token 或 provider 本身有问题
- 直连上游 `200`,但经过本地代理 `401`:代理层 token 配置不同步
- MCP 成功,但宿主客户端失败:宿主客户端走的不是同一条链路,或它自身的 MCP 配置没有生效

### MCP 成功,但宿主客户端不出结果

检查:

- 宿主客户端的 MCP 配置文件里命令、参数和环境变量是否正确
- MCP 工具列表里能否看到 `ask_model`
- 宿主客户端日志里最后一次请求是 `200` 还是 `401`

### `Request timed out after 60000ms`

说明本地 MCP 已经发出请求,但你的上游在设定时间内没有返回。

检查:

- 上游地址是否可达,网络或代理是否正常
- 模型本身是否响应过慢
- `CLAUDE_MCP_TIMEOUT_MS` 是否设置得过小

### PowerShell 里输入中文报错

终端会把自然语言当命令执行。要把问题作为 `prompt` 参数传给 `ask_model`,不能直接在终端敲自然语言。

<a id="known-limitations"></a>
## 已知限制

1. **单工具、非流式**:每次调用发一条新请求,不维护会话状态,不支持流式输出
2. **单 provider**:只认一套环境变量,不做自动切换或 fallback
3. **上游行为不保证**:不同上游的响应行为可能存在差异,建议以实际响应为准
4. **maxTokens 上限 65536**:默认给出更宽松的上限,具体可用值仍然取决于你的上游和模型
5. **默认 60 秒超时**:超时会直接返回错误,需要按上游速度调大 `CLAUDE_MCP_TIMEOUT_MS`

<a id="use-cases"></a>
## 适用场景

- 手里有兼容 Claude Messages API 的上游,但宿主工具只支持 MCP
- 想把上游能力统一包装成一个 MCP 工具供多个客户端复用
- 想先验证「模型和 token 能不能用」,再去排查 UI 和代理问题

不适合:

- 完整聊天应用、多 provider 管理、流式输出、生产级网关

## FAQ

**这是官方 Claude MCP 吗?**
不是,这是本地自建的轻量适配层。

**和直接调 API 相比,这个项目的优势是什么?**
直接调 API 最简单,但每个宿主都要自己实现一遍接入逻辑。这个项目的价值是把上游接口统一包装成 MCP 工具,让多个支持 MCP 的客户端复用同一层适配。

**为什么 Inspector 能用,宿主客户端里不能用?**
两者链路不同。Inspector 通常是最短路径;宿主客户端往往还叠加了自己的配置、权限、日志和工具管理逻辑。排障时必须分层验证。

**模型名写的是 Claude,返回内容像别的产品?**
通常是上游做了包装或角色改写,不是 `server.mjs` 的问题。可以用[验证方式](#verification)章节的方法直接打上游确认原始响应。

<a id="security"></a>
## 安全建议

公开发布这个仓库时,建议保持下面这些边界:

1. `README.md`、`examples/`、`.env.example` 里只放占位符,不放真实 token
2. 本机配置文件、数据库、用户目录下的私有文件不要进入仓库
3. `.env` 这类本地变量文件继续保持在 `.gitignore` 中
4. 如果后面增加更多示例,优先使用 `/path/to/...` 这类通用占位符路径

## 免责声明

本项目仅为技术适配工具,不提供任何 AI 模型服务,不存储任何用户数据。

使用本项目时,你需要自行:

- 确保你使用的上游 API 服务符合其服务条款
- 承担因使用上游服务产生的一切费用、法律责任和风险
- 遵守所在地区关于 AI 服务使用的相关法律法规

本项目作者不对以下情况承担任何责任:

- 上游服务的可用性、准确性或合法性
- 因使用本项目导致的任何直接或间接损失
- 任何第三方服务的条款变更或访问限制

**本软件按"原样"提供,不附带任何明示或暗示的保证。使用风险由用户自行承担。**

TDQS

B3/5.0

Scored across 1 tool

Disambiguation5/5

With only one tool, there is no possibility of ambiguity or overlap between tools. The tool 'ask_model' has a clearly distinct and singular purpose, making misselection impossible.

Naming Consistency5/5

The single tool name 'ask_model' follows a clear verb_noun pattern, and with only one tool, consistency is inherently perfect as there are no other names to compare or deviate from.

Tool Count2/5

A single tool is too few for a server named 'mcp-model-proxy', which suggests a broader scope for model interactions. This minimal set feels thin and likely incomplete for typical proxy functionalities like listing models, managing configurations, or handling different API endpoints.

Completeness2/5

The tool surface is severely incomplete for a model proxy domain. While 'ask_model' covers a core operation, there are significant gaps such as listing available models, configuring model parameters, handling streaming responses, or managing API keys, which will likely cause agent failures in real-world scenarios.

Maintenance

ActivityInactive
ResponsivenessNo issues