cloudflare-mcp-smart-proxy 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +188 -0
- package/index.js +123 -0
- package/package-personal.json +29 -0
- package/package.json +29 -0
- package/publish-now.sh +106 -0
- package/publish-with-2fa.sh +134 -0
- package/publish.sh +90 -0
- package/src/local-tools.js +197 -0
- package/src/router.js +209 -0
- package/src/tools/command-executor.js +82 -0
- package/src/tools/edit-file.js +204 -0
- package/src/tools/file-operations.js +211 -0
package/README.md
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
# @cloudflare-mcp/smart-proxy
|
|
2
|
+
|
|
3
|
+
智能路由代理,自动将 MCP 工具请求路由到云端或本地执行。
|
|
4
|
+
|
|
5
|
+
## 功能特性
|
|
6
|
+
|
|
7
|
+
- ✅ **智能路由**: 自动判断工具应该路由到云端还是本地
|
|
8
|
+
- ✅ **本地文件编辑**: 支持读取、写入、差异编辑本地文件
|
|
9
|
+
- ✅ **云端工具集成**: 无缝使用 Cloudflare MCP 的云端工具
|
|
10
|
+
- ✅ **统一接口**: AI 看到的是合并后的工具列表
|
|
11
|
+
- ✅ **零配置**: 通过 npx 自动安装和使用
|
|
12
|
+
|
|
13
|
+
## 工具路由规则
|
|
14
|
+
|
|
15
|
+
### 本地工具(直接执行)
|
|
16
|
+
|
|
17
|
+
- `read_file` - 读取本地文件
|
|
18
|
+
- `write_file` - 写入本地文件
|
|
19
|
+
- `edit_file` - 差异编辑本地文件
|
|
20
|
+
- `list_dir` - 列出本地目录
|
|
21
|
+
- `delete_file` - 删除本地文件
|
|
22
|
+
- `execute_command` - 执行本地命令
|
|
23
|
+
|
|
24
|
+
### 云端工具(转发到 Cloudflare Workers)
|
|
25
|
+
|
|
26
|
+
- `web_search` - 网络搜索
|
|
27
|
+
- `github_*` - GitHub API 操作
|
|
28
|
+
- `memory_*` - 记忆工具
|
|
29
|
+
- `library_docs` - 库文档查询
|
|
30
|
+
- `codebase_search` - R2 代码库搜索
|
|
31
|
+
- 其他所有未匹配的工具
|
|
32
|
+
|
|
33
|
+
## 安装
|
|
34
|
+
|
|
35
|
+
### 方法 1: 使用安装脚本(推荐)
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
curl -fsSL https://raw.githubusercontent.com/your-repo/local-proxy/main/install.sh | bash
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
或下载后执行:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
chmod +x install.sh
|
|
45
|
+
./install.sh
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 方法 2: 手动配置
|
|
49
|
+
|
|
50
|
+
1. 在 Cursor 配置文件中添加:
|
|
51
|
+
|
|
52
|
+
**~/.cursor/mcp.json** (macOS/Linux)
|
|
53
|
+
**%APPDATA%\Cursor\mcp.json** (Windows)
|
|
54
|
+
|
|
55
|
+
```json
|
|
56
|
+
{
|
|
57
|
+
"mcpServers": {
|
|
58
|
+
"cloudflare-mcp": {
|
|
59
|
+
"type": "stdio",
|
|
60
|
+
"command": "npx",
|
|
61
|
+
"args": ["-y", "@cloudflare-mcp/smart-proxy"],
|
|
62
|
+
"env": {
|
|
63
|
+
"CLOUDFLARE_MCP_URL": "https://your-worker.workers.dev",
|
|
64
|
+
"CLOUDFLARE_MCP_API_KEY": "your_api_key_here",
|
|
65
|
+
"WORKSPACE_ROOT": "/path/to/your/workspace"
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
2. 重启 Cursor IDE
|
|
73
|
+
|
|
74
|
+
## 环境变量
|
|
75
|
+
|
|
76
|
+
| 变量名 | 必需 | 说明 |
|
|
77
|
+
|--------|------|------|
|
|
78
|
+
| `CLOUDFLARE_MCP_URL` | ✅ | Cloudflare MCP 服务器 URL |
|
|
79
|
+
| `CLOUDFLARE_MCP_API_KEY` | ✅ | API Key |
|
|
80
|
+
| `WORKSPACE_ROOT` | ❌ | 工作目录根路径(默认: 当前目录) |
|
|
81
|
+
|
|
82
|
+
## 使用示例
|
|
83
|
+
|
|
84
|
+
### 读取本地文件
|
|
85
|
+
|
|
86
|
+
```json
|
|
87
|
+
{
|
|
88
|
+
"tool": "read_file",
|
|
89
|
+
"params": {
|
|
90
|
+
"target_file": "src/index.js",
|
|
91
|
+
"offset": 0,
|
|
92
|
+
"limit": 50
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### 差异编辑文件
|
|
98
|
+
|
|
99
|
+
```json
|
|
100
|
+
{
|
|
101
|
+
"tool": "edit_file",
|
|
102
|
+
"params": {
|
|
103
|
+
"path": "src/index.js",
|
|
104
|
+
"edits": [
|
|
105
|
+
{
|
|
106
|
+
"type": "replace",
|
|
107
|
+
"startLine": 10,
|
|
108
|
+
"endLine": 12,
|
|
109
|
+
"oldText": "const x = 1;\nconst y = 2;",
|
|
110
|
+
"newText": "const x = 1;\nconst y = 3;\nconst z = 4;"
|
|
111
|
+
}
|
|
112
|
+
],
|
|
113
|
+
"originalContent": "..."
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### 执行本地命令
|
|
119
|
+
|
|
120
|
+
```json
|
|
121
|
+
{
|
|
122
|
+
"tool": "execute_command",
|
|
123
|
+
"params": {
|
|
124
|
+
"command": "npm test",
|
|
125
|
+
"cwd": "."
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## 安全特性
|
|
131
|
+
|
|
132
|
+
- ✅ 路径验证:防止路径遍历攻击
|
|
133
|
+
- ✅ 工作目录限制:只能访问指定目录内的文件
|
|
134
|
+
- ✅ 命令黑名单:禁止执行危险命令
|
|
135
|
+
- ✅ 超时保护:命令执行 30 秒超时
|
|
136
|
+
|
|
137
|
+
## 故障排除
|
|
138
|
+
|
|
139
|
+
### 问题 1: 无法连接到云端服务器
|
|
140
|
+
|
|
141
|
+
**检查**:
|
|
142
|
+
1. 确认 `CLOUDFLARE_MCP_URL` 正确
|
|
143
|
+
2. 确认 `CLOUDFLARE_MCP_API_KEY` 有效
|
|
144
|
+
3. 检查网络连接
|
|
145
|
+
|
|
146
|
+
### 问题 2: 本地文件操作失败
|
|
147
|
+
|
|
148
|
+
**检查**:
|
|
149
|
+
1. 确认文件路径在工作目录内
|
|
150
|
+
2. 检查文件权限
|
|
151
|
+
3. 确认路径不包含 `..`
|
|
152
|
+
|
|
153
|
+
### 问题 3: Cursor 无法识别服务器
|
|
154
|
+
|
|
155
|
+
**检查**:
|
|
156
|
+
1. 重启 Cursor IDE
|
|
157
|
+
2. 检查配置文件 JSON 格式
|
|
158
|
+
3. 查看 Cursor 开发者工具中的错误日志
|
|
159
|
+
|
|
160
|
+
## 开发
|
|
161
|
+
|
|
162
|
+
### 本地测试
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
cd local-proxy
|
|
166
|
+
npm install
|
|
167
|
+
export CLOUDFLARE_MCP_URL="https://your-worker.workers.dev"
|
|
168
|
+
export CLOUDFLARE_MCP_API_KEY="your_key"
|
|
169
|
+
export WORKSPACE_ROOT="/path/to/workspace"
|
|
170
|
+
node index.js
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### 发布到 npm
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
npm login
|
|
177
|
+
npm publish --access public
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## 许可证
|
|
181
|
+
|
|
182
|
+
MIT
|
|
183
|
+
|
|
184
|
+
## 相关链接
|
|
185
|
+
|
|
186
|
+
- [Cloudflare MCP 主项目](../README.md)
|
|
187
|
+
- [MCP 协议文档](https://modelcontextprotocol.io/)
|
|
188
|
+
|
package/index.js
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Cloudflare MCP Smart Proxy
|
|
5
|
+
* 智能路由代理:自动将工具请求路由到云端或本地执行
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
9
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
10
|
+
import { SmartRouter } from './src/router.js';
|
|
11
|
+
import { LocalToolExecutor } from './src/local-tools.js';
|
|
12
|
+
|
|
13
|
+
// 从环境变量读取配置
|
|
14
|
+
const CLOUD_URL = process.env.CLOUDFLARE_MCP_URL || process.env.MCP_URL;
|
|
15
|
+
const CLOUD_API_KEY = process.env.CLOUDFLARE_MCP_API_KEY || process.env.MCP_API_KEY;
|
|
16
|
+
const WORKSPACE_ROOT = process.env.WORKSPACE_ROOT || process.cwd();
|
|
17
|
+
|
|
18
|
+
if (!CLOUD_URL || !CLOUD_API_KEY) {
|
|
19
|
+
console.error('Error: CLOUDFLARE_MCP_URL and CLOUDFLARE_MCP_API_KEY environment variables are required');
|
|
20
|
+
console.error('');
|
|
21
|
+
console.error('Please set:');
|
|
22
|
+
console.error(' export CLOUDFLARE_MCP_URL="https://your-worker.workers.dev"');
|
|
23
|
+
console.error(' export CLOUDFLARE_MCP_API_KEY="your_api_key"');
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// 初始化组件
|
|
28
|
+
const localTools = new LocalToolExecutor(WORKSPACE_ROOT);
|
|
29
|
+
const router = new SmartRouter(CLOUD_URL, CLOUD_API_KEY, localTools);
|
|
30
|
+
|
|
31
|
+
// 创建 MCP 服务器
|
|
32
|
+
const server = new Server(
|
|
33
|
+
{
|
|
34
|
+
name: 'cloudflare-mcp-smart-proxy',
|
|
35
|
+
version: '1.0.0',
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
capabilities: {
|
|
39
|
+
tools: {},
|
|
40
|
+
},
|
|
41
|
+
}
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
// 工具列表处理器
|
|
45
|
+
server.setRequestHandler('tools/list', async () => {
|
|
46
|
+
try {
|
|
47
|
+
const tools = await router.getAllTools();
|
|
48
|
+
return { tools };
|
|
49
|
+
} catch (error) {
|
|
50
|
+
console.error('Error listing tools:', error);
|
|
51
|
+
return { tools: [] };
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// 工具调用处理器
|
|
56
|
+
server.setRequestHandler('tools/call', async (request) => {
|
|
57
|
+
const { name, arguments: args } = request.params;
|
|
58
|
+
|
|
59
|
+
if (!name) {
|
|
60
|
+
return {
|
|
61
|
+
content: [
|
|
62
|
+
{
|
|
63
|
+
type: 'text',
|
|
64
|
+
text: 'Error: Tool name is required'
|
|
65
|
+
}
|
|
66
|
+
],
|
|
67
|
+
isError: true
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
const result = await router.executeTool(name, args || {});
|
|
73
|
+
|
|
74
|
+
// 格式化响应
|
|
75
|
+
if (typeof result === 'string') {
|
|
76
|
+
return {
|
|
77
|
+
content: [{ type: 'text', text: result }],
|
|
78
|
+
isError: false
|
|
79
|
+
};
|
|
80
|
+
} else if (result && typeof result === 'object') {
|
|
81
|
+
return {
|
|
82
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
83
|
+
isError: false
|
|
84
|
+
};
|
|
85
|
+
} else {
|
|
86
|
+
return {
|
|
87
|
+
content: [{ type: 'text', text: String(result) }],
|
|
88
|
+
isError: false
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
} catch (error) {
|
|
92
|
+
console.error(`Error executing tool ${name}:`, error);
|
|
93
|
+
return {
|
|
94
|
+
content: [
|
|
95
|
+
{
|
|
96
|
+
type: 'text',
|
|
97
|
+
text: `Error: ${error.message}`
|
|
98
|
+
}
|
|
99
|
+
],
|
|
100
|
+
isError: true
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// 启动服务器
|
|
106
|
+
async function main() {
|
|
107
|
+
try {
|
|
108
|
+
const transport = new StdioServerTransport();
|
|
109
|
+
await server.connect(transport);
|
|
110
|
+
console.error('Cloudflare MCP Smart Proxy started');
|
|
111
|
+
console.error(`Workspace root: ${WORKSPACE_ROOT}`);
|
|
112
|
+
console.error(`Cloud URL: ${CLOUD_URL}`);
|
|
113
|
+
} catch (error) {
|
|
114
|
+
console.error('Failed to start server:', error);
|
|
115
|
+
process.exit(1);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
main().catch((error) => {
|
|
120
|
+
console.error('Fatal error:', error);
|
|
121
|
+
process.exit(1);
|
|
122
|
+
});
|
|
123
|
+
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "cloudflare-mcp-smart-proxy",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Smart proxy for Cloudflare MCP - routes tools to cloud or local execution",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"cloudflare-mcp-proxy": "./index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"start": "node index.js"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"mcp",
|
|
15
|
+
"cloudflare",
|
|
16
|
+
"proxy",
|
|
17
|
+
"local",
|
|
18
|
+
"filesystem"
|
|
19
|
+
],
|
|
20
|
+
"author": "",
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
24
|
+
},
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=18.0.0"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "cloudflare-mcp-smart-proxy",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Smart proxy for Cloudflare MCP - routes tools to cloud or local execution",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"cloudflare-mcp-proxy": "./index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"start": "node index.js"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"mcp",
|
|
15
|
+
"cloudflare",
|
|
16
|
+
"proxy",
|
|
17
|
+
"local",
|
|
18
|
+
"filesystem"
|
|
19
|
+
],
|
|
20
|
+
"author": "",
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
24
|
+
},
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=18.0.0"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
package/publish-now.sh
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# 快速发布脚本
|
|
4
|
+
|
|
5
|
+
set -e
|
|
6
|
+
|
|
7
|
+
cd "$(dirname "$0")"
|
|
8
|
+
|
|
9
|
+
echo "📦 发布 Cloudflare MCP Smart Proxy"
|
|
10
|
+
echo "=================================="
|
|
11
|
+
echo ""
|
|
12
|
+
|
|
13
|
+
# 检查登录
|
|
14
|
+
if ! npm whoami &> /dev/null; then
|
|
15
|
+
echo "⚠️ 需要先登录 npm"
|
|
16
|
+
echo ""
|
|
17
|
+
echo "运行: npm login"
|
|
18
|
+
echo ""
|
|
19
|
+
read -p "是否现在登录?(y/n) " -n 1 -r
|
|
20
|
+
echo ""
|
|
21
|
+
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
|
22
|
+
npm login
|
|
23
|
+
else
|
|
24
|
+
echo "❌ 取消"
|
|
25
|
+
exit 1
|
|
26
|
+
fi
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
echo "✅ 已登录为: $(npm whoami)"
|
|
30
|
+
echo ""
|
|
31
|
+
|
|
32
|
+
# 选择发布方式
|
|
33
|
+
echo "选择发布方式:"
|
|
34
|
+
echo "1. 组织包 (@cloudflare-mcp/smart-proxy) - 需要组织权限"
|
|
35
|
+
echo "2. 个人包 (cloudflare-mcp-smart-proxy) - 无需组织权限"
|
|
36
|
+
echo ""
|
|
37
|
+
read -p "请选择 (1/2) [默认: 2]: " choice
|
|
38
|
+
choice=${choice:-2}
|
|
39
|
+
|
|
40
|
+
if [ "$choice" == "1" ]; then
|
|
41
|
+
PACKAGE_NAME="@cloudflare-mcp/smart-proxy"
|
|
42
|
+
echo "使用组织包名: $PACKAGE_NAME"
|
|
43
|
+
echo "⚠️ 需要 @cloudflare-mcp 组织权限"
|
|
44
|
+
else
|
|
45
|
+
PACKAGE_NAME="cloudflare-mcp-smart-proxy"
|
|
46
|
+
echo "使用个人包名: $PACKAGE_NAME"
|
|
47
|
+
|
|
48
|
+
# 备份原 package.json
|
|
49
|
+
if [ -f "package.json" ]; then
|
|
50
|
+
cp package.json package.json.backup
|
|
51
|
+
echo "✅ 已备份 package.json"
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
# 使用个人包名
|
|
55
|
+
cp package-personal.json package.json
|
|
56
|
+
echo "✅ 已切换到个人包名"
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
echo ""
|
|
60
|
+
read -p "确认发布?(y/n) " -n 1 -r
|
|
61
|
+
echo ""
|
|
62
|
+
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
63
|
+
echo "❌ 取消"
|
|
64
|
+
# 恢复原配置
|
|
65
|
+
if [ -f "package.json.backup" ]; then
|
|
66
|
+
mv package.json.backup package.json
|
|
67
|
+
fi
|
|
68
|
+
exit 1
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
echo ""
|
|
72
|
+
echo "🚀 发布中..."
|
|
73
|
+
npm publish --access public
|
|
74
|
+
|
|
75
|
+
if [ $? -eq 0 ]; then
|
|
76
|
+
echo ""
|
|
77
|
+
echo "=================================="
|
|
78
|
+
echo "✅ 发布成功!"
|
|
79
|
+
echo ""
|
|
80
|
+
echo "包地址: https://www.npmjs.com/package/$PACKAGE_NAME"
|
|
81
|
+
echo ""
|
|
82
|
+
echo "安装方式:"
|
|
83
|
+
if [ "$choice" == "1" ]; then
|
|
84
|
+
echo " npx -y @cloudflare-mcp/smart-proxy"
|
|
85
|
+
else
|
|
86
|
+
echo " npx -y cloudflare-mcp-smart-proxy"
|
|
87
|
+
echo ""
|
|
88
|
+
echo "⚠️ 注意: 如果使用个人包名,需要更新 CURSOR_配置示例.json 中的包名"
|
|
89
|
+
fi
|
|
90
|
+
echo ""
|
|
91
|
+
|
|
92
|
+
# 恢复原配置
|
|
93
|
+
if [ -f "package.json.backup" ]; then
|
|
94
|
+
mv package.json.backup package.json
|
|
95
|
+
echo "✅ 已恢复原 package.json"
|
|
96
|
+
fi
|
|
97
|
+
else
|
|
98
|
+
echo ""
|
|
99
|
+
echo "❌ 发布失败"
|
|
100
|
+
# 恢复原配置
|
|
101
|
+
if [ -f "package.json.backup" ]; then
|
|
102
|
+
mv package.json.backup package.json
|
|
103
|
+
fi
|
|
104
|
+
exit 1
|
|
105
|
+
fi
|
|
106
|
+
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# 发布脚本 - 带 2FA 检查
|
|
4
|
+
|
|
5
|
+
set -e
|
|
6
|
+
|
|
7
|
+
cd "$(dirname "$0")"
|
|
8
|
+
|
|
9
|
+
echo "📦 发布 Cloudflare MCP Smart Proxy"
|
|
10
|
+
echo "=================================="
|
|
11
|
+
echo ""
|
|
12
|
+
|
|
13
|
+
# 检查登录
|
|
14
|
+
if ! npm whoami &> /dev/null; then
|
|
15
|
+
echo "⚠️ 需要先登录 npm"
|
|
16
|
+
npm login
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
echo "✅ 已登录为: $(npm whoami)"
|
|
20
|
+
echo ""
|
|
21
|
+
|
|
22
|
+
# 检查 2FA 状态
|
|
23
|
+
echo "检查 2FA 状态..."
|
|
24
|
+
PROFILE=$(npm profile get 2>&1)
|
|
25
|
+
if echo "$PROFILE" | grep -q '"twoFactor":"auth-and-writes"'; then
|
|
26
|
+
echo "✅ 2FA 已启用(发布权限)"
|
|
27
|
+
elif echo "$PROFILE" | grep -q '"twoFactor":"auth-only"'; then
|
|
28
|
+
echo "⚠️ 2FA 已启用,但可能没有发布权限"
|
|
29
|
+
echo " 请访问: https://www.npmjs.com/settings/$(npm whoami)/two-factor"
|
|
30
|
+
echo " 确保选择了 'Authorization and Publishing'"
|
|
31
|
+
read -p "继续发布?(y/n) " -n 1 -r
|
|
32
|
+
echo ""
|
|
33
|
+
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
34
|
+
exit 1
|
|
35
|
+
fi
|
|
36
|
+
else
|
|
37
|
+
echo "❌ 2FA 未启用"
|
|
38
|
+
echo ""
|
|
39
|
+
echo "npm 现在要求启用 2FA 才能发布包。"
|
|
40
|
+
echo ""
|
|
41
|
+
echo "请执行以下步骤:"
|
|
42
|
+
echo "1. 访问: https://www.npmjs.com/settings/$(npm whoami)/two-factor"
|
|
43
|
+
echo "2. 启用 2FA,选择 'Authorization and Publishing'"
|
|
44
|
+
echo "3. 使用手机应用(如 Google Authenticator)扫描二维码"
|
|
45
|
+
echo "4. 完成后重新运行此脚本"
|
|
46
|
+
echo ""
|
|
47
|
+
read -p "是否已启用 2FA?(y/n) " -n 1 -r
|
|
48
|
+
echo ""
|
|
49
|
+
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
50
|
+
echo "请先启用 2FA,然后重新运行此脚本"
|
|
51
|
+
exit 1
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
# 重新登录以启用 2FA
|
|
55
|
+
echo "重新登录以应用 2FA..."
|
|
56
|
+
npm logout
|
|
57
|
+
npm login
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
echo ""
|
|
61
|
+
|
|
62
|
+
# 选择发布方式
|
|
63
|
+
echo "选择发布方式:"
|
|
64
|
+
echo "1. 组织包 (@cloudflare-mcp/smart-proxy) - 需要组织权限"
|
|
65
|
+
echo "2. 个人包 (cloudflare-mcp-smart-proxy) - 无需组织权限"
|
|
66
|
+
echo ""
|
|
67
|
+
read -p "请选择 (1/2) [默认: 2]: " choice
|
|
68
|
+
choice=${choice:-2}
|
|
69
|
+
|
|
70
|
+
if [ "$choice" == "1" ]; then
|
|
71
|
+
PACKAGE_NAME="@cloudflare-mcp/smart-proxy"
|
|
72
|
+
echo "使用组织包名: $PACKAGE_NAME"
|
|
73
|
+
echo "⚠️ 需要 @cloudflare-mcp 组织权限"
|
|
74
|
+
else
|
|
75
|
+
PACKAGE_NAME="cloudflare-mcp-smart-proxy"
|
|
76
|
+
echo "使用个人包名: $PACKAGE_NAME"
|
|
77
|
+
|
|
78
|
+
# 备份原 package.json
|
|
79
|
+
if [ -f "package.json" ] && ! grep -q "cloudflare-mcp-smart-proxy" package.json; then
|
|
80
|
+
cp package.json package.json.backup
|
|
81
|
+
echo "✅ 已备份 package.json"
|
|
82
|
+
|
|
83
|
+
# 使用个人包名
|
|
84
|
+
cp package-personal.json package.json
|
|
85
|
+
echo "✅ 已切换到个人包名"
|
|
86
|
+
fi
|
|
87
|
+
fi
|
|
88
|
+
|
|
89
|
+
echo ""
|
|
90
|
+
read -p "确认发布?(y/n) " -n 1 -r
|
|
91
|
+
echo ""
|
|
92
|
+
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
93
|
+
echo "❌ 取消"
|
|
94
|
+
# 恢复原配置
|
|
95
|
+
if [ -f "package.json.backup" ]; then
|
|
96
|
+
mv package.json.backup package.json
|
|
97
|
+
fi
|
|
98
|
+
exit 1
|
|
99
|
+
fi
|
|
100
|
+
|
|
101
|
+
echo ""
|
|
102
|
+
echo "🚀 发布中..."
|
|
103
|
+
npm publish --access public
|
|
104
|
+
|
|
105
|
+
if [ $? -eq 0 ]; then
|
|
106
|
+
echo ""
|
|
107
|
+
echo "=================================="
|
|
108
|
+
echo "✅ 发布成功!"
|
|
109
|
+
echo ""
|
|
110
|
+
echo "包地址: https://www.npmjs.com/package/$PACKAGE_NAME"
|
|
111
|
+
echo ""
|
|
112
|
+
echo "安装方式:"
|
|
113
|
+
if [ "$choice" == "1" ]; then
|
|
114
|
+
echo " npx -y @cloudflare-mcp/smart-proxy"
|
|
115
|
+
else
|
|
116
|
+
echo " npx -y cloudflare-mcp-smart-proxy"
|
|
117
|
+
fi
|
|
118
|
+
echo ""
|
|
119
|
+
|
|
120
|
+
# 恢复原配置
|
|
121
|
+
if [ -f "package.json.backup" ]; then
|
|
122
|
+
mv package.json.backup package.json
|
|
123
|
+
echo "✅ 已恢复原 package.json"
|
|
124
|
+
fi
|
|
125
|
+
else
|
|
126
|
+
echo ""
|
|
127
|
+
echo "❌ 发布失败"
|
|
128
|
+
# 恢复原配置
|
|
129
|
+
if [ -f "package.json.backup" ]; then
|
|
130
|
+
mv package.json.backup package.json
|
|
131
|
+
fi
|
|
132
|
+
exit 1
|
|
133
|
+
fi
|
|
134
|
+
|
package/publish.sh
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# 发布脚本 - 发布 @cloudflare-mcp/smart-proxy 到 npm
|
|
4
|
+
|
|
5
|
+
set -e
|
|
6
|
+
|
|
7
|
+
echo "📦 准备发布 @cloudflare-mcp/smart-proxy 到 npm"
|
|
8
|
+
echo "=============================================="
|
|
9
|
+
echo ""
|
|
10
|
+
|
|
11
|
+
# 检查是否在正确的目录
|
|
12
|
+
if [ ! -f "package.json" ]; then
|
|
13
|
+
echo "❌ 错误: 请在 local-proxy 目录中运行此脚本"
|
|
14
|
+
exit 1
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
# 检查 npm 是否安装
|
|
18
|
+
if ! command -v npm &> /dev/null; then
|
|
19
|
+
echo "❌ 错误: 需要安装 npm"
|
|
20
|
+
exit 1
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
echo "✅ npm 版本: $(npm -v)"
|
|
24
|
+
echo ""
|
|
25
|
+
|
|
26
|
+
# 检查是否登录
|
|
27
|
+
echo "检查 npm 登录状态..."
|
|
28
|
+
if ! npm whoami &> /dev/null; then
|
|
29
|
+
echo "⚠️ 未登录 npm,请先登录:"
|
|
30
|
+
echo ""
|
|
31
|
+
echo "运行: npm login"
|
|
32
|
+
echo ""
|
|
33
|
+
read -p "是否现在登录?(y/n) " -n 1 -r
|
|
34
|
+
echo ""
|
|
35
|
+
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
|
36
|
+
npm login
|
|
37
|
+
else
|
|
38
|
+
echo "❌ 取消发布"
|
|
39
|
+
exit 1
|
|
40
|
+
fi
|
|
41
|
+
else
|
|
42
|
+
echo "✅ 已登录为: $(npm whoami)"
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
echo ""
|
|
46
|
+
|
|
47
|
+
# 检查包名是否可用(需要组织权限)
|
|
48
|
+
PACKAGE_NAME="@cloudflare-mcp/smart-proxy"
|
|
49
|
+
echo "检查包名: $PACKAGE_NAME"
|
|
50
|
+
|
|
51
|
+
# 检查版本
|
|
52
|
+
CURRENT_VERSION=$(node -p "require('./package.json').version")
|
|
53
|
+
echo "当前版本: $CURRENT_VERSION"
|
|
54
|
+
echo ""
|
|
55
|
+
|
|
56
|
+
# 确认发布
|
|
57
|
+
read -p "确认发布到 npm?(y/n) " -n 1 -r
|
|
58
|
+
echo ""
|
|
59
|
+
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
60
|
+
echo "❌ 取消发布"
|
|
61
|
+
exit 1
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
# 运行测试(如果有)
|
|
65
|
+
if [ -f "package.json" ] && grep -q '"test"' package.json; then
|
|
66
|
+
echo "运行测试..."
|
|
67
|
+
npm test || echo "⚠️ 测试失败,但继续发布..."
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
# 发布
|
|
71
|
+
echo ""
|
|
72
|
+
echo "🚀 发布中..."
|
|
73
|
+
npm publish --access public
|
|
74
|
+
|
|
75
|
+
if [ $? -eq 0 ]; then
|
|
76
|
+
echo ""
|
|
77
|
+
echo "=============================================="
|
|
78
|
+
echo "✅ 发布成功!"
|
|
79
|
+
echo ""
|
|
80
|
+
echo "包地址: https://www.npmjs.com/package/@cloudflare-mcp/smart-proxy"
|
|
81
|
+
echo ""
|
|
82
|
+
echo "安装方式:"
|
|
83
|
+
echo " npx -y @cloudflare-mcp/smart-proxy"
|
|
84
|
+
echo ""
|
|
85
|
+
else
|
|
86
|
+
echo ""
|
|
87
|
+
echo "❌ 发布失败"
|
|
88
|
+
exit 1
|
|
89
|
+
fi
|
|
90
|
+
|