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.
@@ -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
+ }