arl-next-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.
Files changed (3) hide show
  1. package/README.md +36 -0
  2. package/index.js +183 -0
  3. package/package.json +25 -0
package/README.md ADDED
@@ -0,0 +1,36 @@
1
+ # ARL-Next MCP Server
2
+
3
+ 这是 [ARL-Next](https://github.com/owl234/ARL-Next) 的官方 MCP (Model Context Protocol) 服务代理。
4
+
5
+ 该模块作为一个中间代理,允许 AI 助手(如 Cursor, Claude Desktop 等)安全地通过你的本地环境与远端的 ARL-Next 服务进行交互,**无需在公网服务端暴露额外端口**。
6
+
7
+ ## 🚀 快速接入
8
+
9
+ **完全无需本地安装!** 只需在你的 AI 客户端(如 Cursor 或 Claude)的 MCP 配置文件中添加以下内容:
10
+
11
+ ```json
12
+ {
13
+ "mcpServers": {
14
+ "ARL-Next": {
15
+ "command": "npx",
16
+ "args": [
17
+ "-y",
18
+ "@arl-next/mcp"
19
+ ],
20
+ "env": {
21
+ "ARL_HOST": "https://你的服务器IP",
22
+ "ARL_TOKEN": "你的API_TOKEN"
23
+ }
24
+ }
25
+ }
26
+ }
27
+ ```
28
+ 3. **重启加载**:
29
+ 保存文件后,重启您的 Antigravity IDE 即可。当您在侧边栏或代码助手对话时,就可以直接让它去“搜索 ARL 最新资产”了。
30
+
31
+ ## 🛠️ 当前支持的 Tools
32
+
33
+ 1. `search_assets`:从资产库中智能查询资产(支持 `site`, `ip`, `domain`, `cert`, `service` 类型)。
34
+ 2. `get_tasks`:获取最近的扫描任务状态。
35
+
36
+ 更多自动化漏洞分析和下发任务功能持续更新中...
package/index.js ADDED
@@ -0,0 +1,183 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { Server } = require("@modelcontextprotocol/sdk/server/index.js");
4
+ const { StdioServerTransport } = require("@modelcontextprotocol/sdk/server/stdio.js");
5
+ const {
6
+ CallToolRequestSchema,
7
+ ListToolsRequestSchema,
8
+ } = require("@modelcontextprotocol/sdk/types.js");
9
+ const axios = require("axios");
10
+ const { program } = require("commander");
11
+
12
+ program
13
+ .name("arl-mcp")
14
+ .description("MCP Server for ARL-Next")
15
+ .option("--host <host>", "ARL-Next server host URL (e.g. https://1.1.1.1:5173)")
16
+ .option("--token <token>", "ARL-Next API token")
17
+ .parse(process.argv);
18
+
19
+ const options = program.opts();
20
+ const host = options.host || process.env.ARL_HOST;
21
+ const token = options.token || process.env.ARL_TOKEN;
22
+
23
+ if (!host || !token) {
24
+ console.error("Error: --host and --token are required. Provide them via CLI or environment variables (ARL_HOST, ARL_TOKEN).");
25
+ process.exit(1);
26
+ }
27
+
28
+ const https = require("https");
29
+
30
+ const apiClient = axios.create({
31
+ baseURL: `${host}/api`,
32
+ headers: {
33
+ "Token": token
34
+ },
35
+ timeout: 10000,
36
+ httpsAgent: new https.Agent({
37
+ rejectUnauthorized: false
38
+ })
39
+ });
40
+
41
+ const server = new Server(
42
+ {
43
+ name: "arl-next-mcp",
44
+ version: "1.0.0",
45
+ },
46
+ {
47
+ capabilities: {
48
+ tools: {},
49
+ },
50
+ }
51
+ );
52
+
53
+ // Define tools
54
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
55
+ return {
56
+ tools: [
57
+ {
58
+ name: "search_assets",
59
+ description: "Search for discovered assets (sites, IPs, domains) in ARL-Next.",
60
+ inputSchema: {
61
+ type: "object",
62
+ properties: {
63
+ assetType: {
64
+ type: "string",
65
+ description: "Type of asset to search: 'site', 'ip', 'domain', 'cert', 'service'",
66
+ enum: ["site", "ip", "domain", "cert", "service"]
67
+ },
68
+ query: {
69
+ type: "string",
70
+ description: "Search keyword (e.g. 'nginx', '1.1.1.1', 'example.com')"
71
+ },
72
+ page: {
73
+ type: "number",
74
+ description: "Page number (default 1)"
75
+ },
76
+ size: {
77
+ type: "number",
78
+ description: "Page size (default 10, max 50 for safety)"
79
+ }
80
+ },
81
+ required: ["assetType"]
82
+ }
83
+ },
84
+ {
85
+ name: "get_tasks",
86
+ description: "Get recent scanning tasks and their status.",
87
+ inputSchema: {
88
+ type: "object",
89
+ properties: {
90
+ page: { type: "number", description: "Page number (default 1)" },
91
+ size: { type: "number", description: "Page size (default 10)" }
92
+ }
93
+ }
94
+ }
95
+ ],
96
+ };
97
+ });
98
+
99
+ // Handle tool execution
100
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
101
+ if (request.params.name === "search_assets") {
102
+ const { assetType, query, page = 1, size = 10 } = request.params.arguments;
103
+
104
+ // Security Fix: Validate assetType to prevent path traversal
105
+ const allowedAssets = ["site", "ip", "domain", "cert", "service"];
106
+ if (!allowedAssets.includes(assetType)) {
107
+ return {
108
+ content: [{ type: "text", text: `Error: Invalid assetType '${assetType}'` }],
109
+ isError: true
110
+ };
111
+ }
112
+
113
+ const safeSize = Math.min(size, 50); // Enforce max 50 to prevent OOM
114
+
115
+ try {
116
+ const response = await apiClient.get(`/${assetType}/`, {
117
+ params: {
118
+ page: page,
119
+ size: safeSize,
120
+ query: query
121
+ }
122
+ });
123
+ return {
124
+ content: [
125
+ {
126
+ type: "text",
127
+ text: JSON.stringify(response.data, null, 2)
128
+ }
129
+ ]
130
+ };
131
+ } catch (error) {
132
+ return {
133
+ content: [
134
+ {
135
+ type: "text",
136
+ text: `API Request Failed: ${error.message}\n${error.response?.data ? JSON.stringify(error.response.data) : ''}`
137
+ }
138
+ ],
139
+ isError: true
140
+ };
141
+ }
142
+ }
143
+
144
+ if (request.params.name === "get_tasks") {
145
+ const { page = 1, size = 10 } = request.params.arguments;
146
+ try {
147
+ const response = await apiClient.get(`/task/`, {
148
+ params: { page, size }
149
+ });
150
+ return {
151
+ content: [
152
+ {
153
+ type: "text",
154
+ text: JSON.stringify(response.data, null, 2)
155
+ }
156
+ ]
157
+ };
158
+ } catch (error) {
159
+ return {
160
+ content: [
161
+ {
162
+ type: "text",
163
+ text: `API Request Failed: ${error.message}\n${error.response?.data ? JSON.stringify(error.response.data) : ''}`
164
+ }
165
+ ],
166
+ isError: true
167
+ };
168
+ }
169
+ }
170
+
171
+ throw new Error("Unknown tool");
172
+ });
173
+
174
+ async function run() {
175
+ const transport = new StdioServerTransport();
176
+ await server.connect(transport);
177
+ console.error("ARL-Next MCP Server running on stdio");
178
+ }
179
+
180
+ run().catch((error) => {
181
+ console.error("Fatal error running MCP server:", error);
182
+ process.exit(1);
183
+ });
package/package.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "arl-next-mcp",
3
+ "version": "1.0.0",
4
+ "description": "ARL-Next MCP Server",
5
+ "main": "index.js",
6
+ "bin": {
7
+ "arl-next-mcp": "index.js"
8
+ },
9
+ "scripts": {
10
+ "test": "echo \"Error: no test specified\" && exit 1"
11
+ },
12
+ "keywords": [
13
+ "mcp",
14
+ "arl-next",
15
+ "security"
16
+ ],
17
+ "author": "ARL-Next",
18
+ "license": "ISC",
19
+ "type": "commonjs",
20
+ "dependencies": {
21
+ "@modelcontextprotocol/sdk": "^1.29.0",
22
+ "axios": "^1.18.1",
23
+ "commander": "^15.0.0"
24
+ }
25
+ }