aira-mcp 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/.vscode/launch.json +29 -0
- package/README.md +256 -0
- package/index.js +158 -0
- package/package.json +28 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
// 使用 IntelliSense 了解相关属性。
|
|
3
|
+
// 悬停以查看现有属性的描述。
|
|
4
|
+
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
|
|
5
|
+
"version": "0.2.0",
|
|
6
|
+
"configurations": [
|
|
7
|
+
{
|
|
8
|
+
"name": "Launch Program",
|
|
9
|
+
"program": "${workspaceFolder}/index.js",
|
|
10
|
+
"args": [
|
|
11
|
+
"--aria2-host=http://localhost:16800"
|
|
12
|
+
],
|
|
13
|
+
"request": "launch",
|
|
14
|
+
"skipFiles": [
|
|
15
|
+
"<node_internals>/**"
|
|
16
|
+
],
|
|
17
|
+
"type": "node"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"type": "node",
|
|
21
|
+
"request": "launch",
|
|
22
|
+
"name": "index",
|
|
23
|
+
"skipFiles": [
|
|
24
|
+
"<node_internals>/**"
|
|
25
|
+
],
|
|
26
|
+
"program": "node ${workspaceFolder}\\index.js --aria2-host=http://localhost:16800"
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
}
|
package/README.md
ADDED
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
# Aira MCP Service
|
|
2
|
+
|
|
3
|
+
使用JavaScript构建的MCP服务,能够通过aria2进行下载,aria服务器地址可以通过npx参数配置传入。
|
|
4
|
+
|
|
5
|
+
## 安装
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 运行
|
|
12
|
+
|
|
13
|
+
### 基本运行
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm start
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### 通过npx参数配置aria服务器地址
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx aira-mcp --aria2-host=localhost --aria2-port=6800 --aria2-secret=your-secret
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### 支持的命令行参数
|
|
26
|
+
|
|
27
|
+
| 参数名 | 描述 | 默认值 |
|
|
28
|
+
|-------|------|--------|
|
|
29
|
+
| --aria2-host | aria2服务器地址或完整URL | localhost |
|
|
30
|
+
| --aria2-port | aria2服务器端口 | 6800 |
|
|
31
|
+
| --aria2-secret | aria2服务器密钥 | 无 |
|
|
32
|
+
| --aria2-secure | 是否使用HTTPS | false |
|
|
33
|
+
| --aria2-path | aria2 JSON-RPC路径 | /jsonrpc |
|
|
34
|
+
|
|
35
|
+
### 示例
|
|
36
|
+
|
|
37
|
+
使用完整URL配置:
|
|
38
|
+
```bash
|
|
39
|
+
npx aira-mcp --aria2-host=http://localhost:6800/jsonrpc
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
使用独立参数配置:
|
|
43
|
+
```bash
|
|
44
|
+
npx aira-mcp --aria2-host=192.168.1.100 --aria2-port=6801 --aria2-secret=mysecret --aria2-secure=false
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## 接口说明
|
|
48
|
+
|
|
49
|
+
### 健康检查
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
GET /health
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
响应:
|
|
56
|
+
```json
|
|
57
|
+
{
|
|
58
|
+
"status": "ok",
|
|
59
|
+
"message": "MCP Service is running"
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### 下载文件
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
POST /download
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
请求体:
|
|
70
|
+
```json
|
|
71
|
+
{
|
|
72
|
+
"uri": "http://example.com/file.zip",
|
|
73
|
+
"options": {
|
|
74
|
+
"dir": "/downloads",
|
|
75
|
+
"max-connection-per-server": 5
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
响应:
|
|
81
|
+
```json
|
|
82
|
+
{
|
|
83
|
+
"success": true,
|
|
84
|
+
"gid": "2089b05ecca3d829",
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Magnet下载
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
POST /download/magnet
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
请求体:
|
|
95
|
+
```json
|
|
96
|
+
{
|
|
97
|
+
"hashkey": "88594AAACBDE40EF3E2510C47374EC0AA396C08E",
|
|
98
|
+
"options": {
|
|
99
|
+
"dir": "/downloads"
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
响应:
|
|
105
|
+
```json
|
|
106
|
+
{
|
|
107
|
+
"success": true,
|
|
108
|
+
"gid": "2089b05ecca3d829",
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### 获取下载状态
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
GET /download/:gid
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
响应:
|
|
119
|
+
```json
|
|
120
|
+
{
|
|
121
|
+
"success": true,
|
|
122
|
+
"status": {
|
|
123
|
+
"gid": "2089b05ecca3d829",
|
|
124
|
+
"status": "active",
|
|
125
|
+
"totalLength": "1000000",
|
|
126
|
+
"completedLength": "500000",
|
|
127
|
+
"uploadLength": "0",
|
|
128
|
+
"bitfield": "eeeeeeeeeeeeeeee",
|
|
129
|
+
"downloadSpeed": "100000",
|
|
130
|
+
"uploadSpeed": "0",
|
|
131
|
+
"infoHash": "",
|
|
132
|
+
"numSeeders": "0",
|
|
133
|
+
"seeder": false,
|
|
134
|
+
"connections": "5",
|
|
135
|
+
"errorCode": "0",
|
|
136
|
+
"errorMessage": "",
|
|
137
|
+
"followedBy": [],
|
|
138
|
+
"following": "",
|
|
139
|
+
"belongsTo": "",
|
|
140
|
+
"dir": "/downloads",
|
|
141
|
+
"files": [
|
|
142
|
+
{
|
|
143
|
+
"index": "1",
|
|
144
|
+
"path": "/downloads/file.zip",
|
|
145
|
+
"length": "1000000",
|
|
146
|
+
"completedLength": "500000",
|
|
147
|
+
"selected": true,
|
|
148
|
+
"uris": [
|
|
149
|
+
{
|
|
150
|
+
"uri": "http://example.com/file.zip",
|
|
151
|
+
"status": "used"
|
|
152
|
+
}
|
|
153
|
+
]
|
|
154
|
+
}
|
|
155
|
+
],
|
|
156
|
+
"bittorrent": null,
|
|
157
|
+
"verifiedLength": "0",
|
|
158
|
+
"verifyIntegrityPending": false
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### 暂停下载
|
|
164
|
+
|
|
165
|
+
```
|
|
166
|
+
POST /download/:gid/pause
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
响应:
|
|
170
|
+
```json
|
|
171
|
+
{
|
|
172
|
+
"success": true,
|
|
173
|
+
"message": "Download paused"
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### 恢复下载
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
POST /download/:gid/resume
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
响应:
|
|
184
|
+
```json
|
|
185
|
+
{
|
|
186
|
+
"success": true,
|
|
187
|
+
"message": "Download resumed"
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### 删除下载
|
|
192
|
+
|
|
193
|
+
```
|
|
194
|
+
DELETE /download/:gid
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
响应:
|
|
198
|
+
```json
|
|
199
|
+
{
|
|
200
|
+
"success": true,
|
|
201
|
+
"message": "Download removed"
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## 配置参数
|
|
206
|
+
|
|
207
|
+
| 参数名 | 描述 | 默认值 |
|
|
208
|
+
|-------|------|--------|
|
|
209
|
+
| --aria2-host | aria2服务器地址 | http://localhost:6800 |
|
|
210
|
+
| --aria2-secret | aria2服务器密钥 | 无 |
|
|
211
|
+
|
|
212
|
+
## MCP配置方式
|
|
213
|
+
|
|
214
|
+
在MCP配置文件中,可以按照以下方式配置Aira MCP Service:
|
|
215
|
+
|
|
216
|
+
```json
|
|
217
|
+
{
|
|
218
|
+
"mcpServers": {
|
|
219
|
+
"aira-mcp": {
|
|
220
|
+
"command": "npx",
|
|
221
|
+
"args": [
|
|
222
|
+
"aira-mcp",
|
|
223
|
+
"--aria2-host=localhost",
|
|
224
|
+
"--aria2-port=6800",
|
|
225
|
+
"--aria2-secret=your-secret"
|
|
226
|
+
]
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### 配置说明
|
|
233
|
+
|
|
234
|
+
- `command`: 使用`npx`命令来执行包
|
|
235
|
+
- `args`: 命令行参数列表
|
|
236
|
+
- `aira-mcp`: 包名
|
|
237
|
+
- `--aria2-host`: aria2服务器地址
|
|
238
|
+
- `--aria2-port`: aria2服务器端口
|
|
239
|
+
- `--aria2-secret`: aria2服务器密钥(可选)
|
|
240
|
+
|
|
241
|
+
### 完整配置示例
|
|
242
|
+
|
|
243
|
+
```json
|
|
244
|
+
{
|
|
245
|
+
"mcpServers": {
|
|
246
|
+
"aira-mcp": {
|
|
247
|
+
"command": "npx",
|
|
248
|
+
"args": [
|
|
249
|
+
"aira-mcp",
|
|
250
|
+
"--aria2-host=http://192.168.1.100:6801/jsonrpc",
|
|
251
|
+
"--aria2-secret=mysecret"
|
|
252
|
+
]
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
```
|
package/index.js
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const express = require('express');
|
|
3
|
+
const Aria2 = require('aria2');
|
|
4
|
+
const app = express();
|
|
5
|
+
const port = 23121;
|
|
6
|
+
|
|
7
|
+
// 解析命令行参数获取aria2服务器配置
|
|
8
|
+
const args = process.argv.slice(2);
|
|
9
|
+
let aria2Host = 'localhost';
|
|
10
|
+
let aria2Port = 6800;
|
|
11
|
+
let aria2Secret = '';
|
|
12
|
+
let aria2Secure = false;
|
|
13
|
+
let aria2Path = '/jsonrpc';
|
|
14
|
+
|
|
15
|
+
for (let i = 0; i < args.length; i++) {
|
|
16
|
+
if (args[i].startsWith('--aria2-host=')) {
|
|
17
|
+
const value = args[i].split('=')[1];
|
|
18
|
+
// 检查是否是完整URL格式
|
|
19
|
+
if (value.startsWith('http://') || value.startsWith('https://')) {
|
|
20
|
+
const url = new URL(value);
|
|
21
|
+
aria2Secure = url.protocol === 'https:';
|
|
22
|
+
aria2Host = url.hostname;
|
|
23
|
+
aria2Port = parseInt(url.port) || (aria2Secure ? 443 : 80);
|
|
24
|
+
// 如果path为空或为"/",使用默认值
|
|
25
|
+
aria2Path = (url.pathname && url.pathname !== '/') ? url.pathname : '/jsonrpc';
|
|
26
|
+
} else {
|
|
27
|
+
// 单独的host参数
|
|
28
|
+
aria2Host = value;
|
|
29
|
+
}
|
|
30
|
+
} else if (args[i].startsWith('--aria2-port=')) {
|
|
31
|
+
aria2Port = parseInt(args[i].split('=')[1]) || 6800;
|
|
32
|
+
} else if (args[i].startsWith('--aria2-secret=')) {
|
|
33
|
+
aria2Secret = args[i].split('=')[1];
|
|
34
|
+
} else if (args[i].startsWith('--aria2-secure=')) {
|
|
35
|
+
aria2Secure = args[i].split('=')[1] === 'true';
|
|
36
|
+
} else if (args[i].startsWith('--aria2-path=')) {
|
|
37
|
+
const value = args[i].split('=')[1];
|
|
38
|
+
aria2Path = value || '/jsonrpc';
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// 创建aria2客户端
|
|
43
|
+
const aria2 = new Aria2({
|
|
44
|
+
secure: aria2Secure,
|
|
45
|
+
host: aria2Host,
|
|
46
|
+
port: aria2Port,
|
|
47
|
+
secret: aria2Secret,
|
|
48
|
+
path: aria2Path
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// 中间件
|
|
52
|
+
app.use(express.json());
|
|
53
|
+
|
|
54
|
+
// 健康检查接口
|
|
55
|
+
app.get('/health', (req, res) => {
|
|
56
|
+
res.json({ status: 'ok', message: 'MCP Service is running' });
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// 下载接口
|
|
60
|
+
app.post('/download', async (req, res) => {
|
|
61
|
+
try {
|
|
62
|
+
const { uri, options } = req.body;
|
|
63
|
+
if (!uri) {
|
|
64
|
+
return res.status(400).json({ error: 'URI is required' });
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const result = await aria2.call('addUri', [uri], options || {});
|
|
68
|
+
res.json({ success: true, gid: result });
|
|
69
|
+
} catch (error) {
|
|
70
|
+
console.error('Error adding URI to aria2:', error);
|
|
71
|
+
res.status(500).json({ error: `Failed to add URI to aria2: ${error.message}` });
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// Magnet下载接口
|
|
76
|
+
app.post('/download/magnet', async (req, res) => {
|
|
77
|
+
try {
|
|
78
|
+
const { hashkey, options } = req.body;
|
|
79
|
+
if (!hashkey) {
|
|
80
|
+
return res.status(400).json({ error: 'Hashkey is required' });
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// 构建magnet URI
|
|
84
|
+
const magnetUri = `magnet:?xt=urn:btih:${hashkey}`;
|
|
85
|
+
const result = await aria2.call('addUri', [magnetUri], options || {});
|
|
86
|
+
res.json({ success: true, gid: result });
|
|
87
|
+
} catch (error) {
|
|
88
|
+
console.error('Error adding magnet to aria2:', error);
|
|
89
|
+
res.status(500).json({ error: `Failed to add magnet to aria2: ${error.message}` });
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// 获取下载状态接口
|
|
94
|
+
app.get('/download/:gid', async (req, res) => {
|
|
95
|
+
try {
|
|
96
|
+
const { gid } = req.params;
|
|
97
|
+
const result = await aria2.call('tellStatus', gid);
|
|
98
|
+
res.json({ success: true, status: result });
|
|
99
|
+
} catch (error) {
|
|
100
|
+
console.error('Error getting download status from aria2:', error);
|
|
101
|
+
res.status(500).json({ error: `Failed to get download status from aria2: ${error.message}` });
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// 暂停下载接口
|
|
106
|
+
app.post('/download/:gid/pause', async (req, res) => {
|
|
107
|
+
try {
|
|
108
|
+
const { gid } = req.params;
|
|
109
|
+
await aria2.call('pause', gid);
|
|
110
|
+
res.json({ success: true, message: 'Download paused' });
|
|
111
|
+
} catch (error) {
|
|
112
|
+
console.error('Error pausing download in aria2:', error);
|
|
113
|
+
res.status(500).json({ error: `Failed to pause download in aria2: ${error.message}` });
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// 恢复下载接口
|
|
118
|
+
app.post('/download/:gid/resume', async (req, res) => {
|
|
119
|
+
try {
|
|
120
|
+
const { gid } = req.params;
|
|
121
|
+
await aria2.call('unpause', gid);
|
|
122
|
+
res.json({ success: true, message: 'Download resumed' });
|
|
123
|
+
} catch (error) {
|
|
124
|
+
console.error('Error resuming download in aria2:', error);
|
|
125
|
+
res.status(500).json({ error: `Failed to resume download in aria2: ${error.message}` });
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// 删除下载接口
|
|
130
|
+
app.delete('/download/:gid', async (req, res) => {
|
|
131
|
+
try {
|
|
132
|
+
const { gid } = req.params;
|
|
133
|
+
await aria2.call('remove', gid);
|
|
134
|
+
res.json({ success: true, message: 'Download removed' });
|
|
135
|
+
} catch (error) {
|
|
136
|
+
console.error('Error removing download from aria2:', error);
|
|
137
|
+
res.status(500).json({ error: `Failed to remove download from aria2: ${error.message}` });
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// 启动服务器
|
|
142
|
+
app.listen(port, () => {
|
|
143
|
+
console.log(`MCP Service running at http://localhost:${port}`);
|
|
144
|
+
console.log(`Configured to connect to aria2 at ${aria2Secure ? 'https' : 'http'}://${aria2Host}:${aria2Port}${aria2Path}`);
|
|
145
|
+
|
|
146
|
+
// 稍后尝试连接aria2服务器
|
|
147
|
+
setTimeout(async () => {
|
|
148
|
+
try {
|
|
149
|
+
// 尝试连接aria2服务器
|
|
150
|
+
await aria2.open();
|
|
151
|
+
console.log('Successfully connected to aria2 server');
|
|
152
|
+
await aria2.close(); // 关闭初始连接
|
|
153
|
+
} catch (error) {
|
|
154
|
+
console.warn(`Warning: Could not connect to aria2 server at ${aria2Secure ? 'https' : 'http'}://${aria2Host}:${aria2Port}${aria2Path}:`, error.message);
|
|
155
|
+
console.log('MCP Service will still run, but aria2 operations will fail until a valid aria2 server is available.');
|
|
156
|
+
}
|
|
157
|
+
}, 1000); // 延迟1秒后尝试连接
|
|
158
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "aira-mcp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"main": "index.js",
|
|
5
|
+
"bin": {
|
|
6
|
+
"aira-mcp": "index.js"
|
|
7
|
+
},
|
|
8
|
+
"scripts": {
|
|
9
|
+
"start": "node index.js",
|
|
10
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"aria2",
|
|
14
|
+
"download",
|
|
15
|
+
"cli",
|
|
16
|
+
"mcp"
|
|
17
|
+
],
|
|
18
|
+
"author": "",
|
|
19
|
+
"license": "ISC",
|
|
20
|
+
"description": "Aria2 MCP (Media Control Protocol) Service CLI",
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"aria2": "4.1.0",
|
|
23
|
+
"express": "^5.2.1"
|
|
24
|
+
},
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=14.0.0"
|
|
27
|
+
}
|
|
28
|
+
}
|