@poolzin/pool-bot 2026.4.32 → 2026.4.34
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/dist/agents/poolbot-tools.d.ts.map +1 -1
- package/dist/agents/poolbot-tools.js +2 -0
- package/dist/agents/system-prompt.d.ts.map +1 -1
- package/dist/agents/system-prompt.js +2 -0
- package/dist/agents/tools/skill-evolve-tool.d.ts.map +1 -1
- package/dist/agents/tools/skill-evolve-tool.js +18 -7
- package/dist/agents/tools/vps-security-tool.d.ts +8 -0
- package/dist/agents/tools/vps-security-tool.d.ts.map +1 -0
- package/dist/agents/tools/vps-security-tool.js +264 -0
- package/dist/build-info.json +3 -3
- package/dist/cli/mcp-cli.d.ts +10 -0
- package/dist/cli/mcp-cli.d.ts.map +1 -0
- package/dist/cli/mcp-cli.js +44 -0
- package/dist/mcp/server.d.ts +39 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +463 -0
- package/docs/mcp-server.md +171 -0
- package/docs/security/vps-hardening.md +309 -0
- package/docs/skills/vps-security.md +140 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"poolbot-tools.d.ts","sourceRoot":"","sources":["../../src/agents/poolbot-tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AAEzE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAI9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"poolbot-tools.d.ts","sourceRoot":"","sources":["../../src/agents/poolbot-tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AAEzE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAI9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAsBtD,wBAAgB,kBAAkB,CAAC,OAAO,CAAC,EAAE;IAC3C,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,qBAAqB,CAAC;IACrC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oFAAoF;IACpF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6EAA6E;IAC7E,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAChC,0DAA0D;IAC1D,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,qEAAqE;IACrE,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,mEAAmE;IACnE,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC/B,qDAAqD;IACrD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,2DAA2D;IAC3D,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,8CAA8C;IAC9C,WAAW,CAAC,EAAE,KAAK,GAAG,OAAO,GAAG,KAAK,CAAC;IACtC,mEAAmE;IACnE,aAAa,CAAC,EAAE;QAAE,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC;IACnC,sDAAsD;IACtD,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,yDAAyD;IACzD,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,uEAAuE;IACvE,4BAA4B,CAAC,EAAE,OAAO,CAAC;IACvC,yDAAyD;IACzD,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B,GAAG,YAAY,EAAE,CAsJjB"}
|
|
@@ -19,6 +19,7 @@ import { createSessionsSendTool } from "./tools/sessions-send-tool.js";
|
|
|
19
19
|
import { createSessionsSpawnTool } from "./tools/sessions-spawn-tool.js";
|
|
20
20
|
import { createSubagentsTool } from "./tools/subagents-tool.js";
|
|
21
21
|
import { createSkillEvolveTool } from "./tools/skill-evolve-tool.js";
|
|
22
|
+
import { createVPSSecurityTool } from "./tools/vps-security-tool.js";
|
|
22
23
|
import { createTtsTool } from "./tools/tts-tool.js";
|
|
23
24
|
import { createWebFetchTool, createWebSearchTool } from "./tools/web-tools.js";
|
|
24
25
|
import { resolveWorkspaceRoot } from "./workspace-dir.js";
|
|
@@ -135,6 +136,7 @@ export function createPoolBotTools(options) {
|
|
|
135
136
|
config: options?.config,
|
|
136
137
|
}),
|
|
137
138
|
createSkillEvolveTool(options?.config ?? {}),
|
|
139
|
+
createVPSSecurityTool(options?.config ?? {}),
|
|
138
140
|
...(webSearchTool ? [webSearchTool] : []),
|
|
139
141
|
...(webFetchTool ? [webFetchTool] : []),
|
|
140
142
|
...(imageTool ? [imageTool] : []),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"system-prompt.d.ts","sourceRoot":"","sources":["../../src/agents/system-prompt.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"system-prompt.d.ts","sourceRoot":"","sources":["../../src/agents/system-prompt.ts"],"names":[],"mappings":"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"}
|
|
@@ -213,6 +213,7 @@ export function buildAgentSystemPrompt(params) {
|
|
|
213
213
|
nodes: "List/describe/notify/camera/screen on paired nodes",
|
|
214
214
|
cron: "Manage cron jobs and wake events. SCHEDULING MODES: (1) Reminders — use systemEvent payload to inject text into your session when it fires; write the text as something that reads like a reminder. (2) Background tasks — use agentTurn payload with a message describing the work; results auto-deliver back to the originating chat. CRITICAL: When the user asks you to do something 'later', 'tonight', 'overnight', 'tomorrow morning', 'when I wake up', or any future time — IMMEDIATELY schedule a cron job with schedule.kind='at' at the appropriate time and payload.kind='agentTurn' with a descriptive message. Do NOT just say you'll do it. Actually schedule it. Use delivery.mode='announce' (default) to deliver results back to the user's chat.",
|
|
215
215
|
skill_evolve: "Self-improve a skill file. Use this when you notice a skill is unclear, incomplete, or could be more effective. The tool loads the skill content and guides you to write an improved version using the 'write' tool. Periodically review and evolve your skills to keep them sharp.",
|
|
216
|
+
vps_security: "Monitor VPS security (fail2ban, UFW, SSH hardening, honeypot). Check status, view banned IPs, unban IPs, check firewall rules, and generate security reports. Use for security monitoring and incident response.",
|
|
216
217
|
message: "Send messages and channel actions",
|
|
217
218
|
gateway: "Restart, apply config, or run updates on the running Pool Bot process",
|
|
218
219
|
agents_list: "List agent ids allowed for sessions_spawn",
|
|
@@ -378,6 +379,7 @@ export function buildAgentSystemPrompt(params) {
|
|
|
378
379
|
"- nodes: list/describe/notify/camera/screen on paired nodes",
|
|
379
380
|
"- cron: manage cron jobs and wake events (use systemEvent for reminders, agentTurn for background tasks; when user asks for future work — 'later', 'tonight', 'tomorrow' — schedule an agentTurn cron job with schedule.kind='at')",
|
|
380
381
|
"- skill_evolve: self-improve skill files (review, optimize, write improved version)",
|
|
382
|
+
"- vps_security: monitor VPS security (fail2ban, UFW, SSH hardening, honeypot; check status, unban IPs, generate reports)",
|
|
381
383
|
"- sessions_list: list sessions",
|
|
382
384
|
"- sessions_history: fetch session history",
|
|
383
385
|
"- sessions_send: send to another session",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skill-evolve-tool.d.ts","sourceRoot":"","sources":["../../../src/agents/tools/skill-evolve-tool.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAE5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAKhD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,aAAa,GAAG,YAAY,
|
|
1
|
+
{"version":3,"file":"skill-evolve-tool.d.ts","sourceRoot":"","sources":["../../../src/agents/tools/skill-evolve-tool.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAE5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAKhD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,aAAa,GAAG,YAAY,CAqGtE"}
|
|
@@ -34,7 +34,12 @@ export function createSkillEvolveTool(cfg) {
|
|
|
34
34
|
const skillName = readStringParam(params, "skill", { required: true });
|
|
35
35
|
if (!skillName) {
|
|
36
36
|
return {
|
|
37
|
-
content: [
|
|
37
|
+
content: [
|
|
38
|
+
{
|
|
39
|
+
type: "text",
|
|
40
|
+
text: "Error: 'skill' parameter is required. Provide a skill name or path.",
|
|
41
|
+
},
|
|
42
|
+
],
|
|
38
43
|
};
|
|
39
44
|
}
|
|
40
45
|
const focus = typeof params.focus === "string" ? params.focus : "all";
|
|
@@ -50,19 +55,22 @@ export function createSkillEvolveTool(cfg) {
|
|
|
50
55
|
}
|
|
51
56
|
if (!skillPath) {
|
|
52
57
|
return {
|
|
53
|
-
content: [
|
|
58
|
+
content: [
|
|
59
|
+
{
|
|
54
60
|
type: "text",
|
|
55
61
|
text: `Skill '${skillName}' not found.\n` +
|
|
56
62
|
`Searched in: ${skillsDir}/\n` +
|
|
57
63
|
`Use the 'read' tool to list available skills first.`,
|
|
58
|
-
}
|
|
64
|
+
},
|
|
65
|
+
],
|
|
59
66
|
};
|
|
60
67
|
}
|
|
61
68
|
try {
|
|
62
69
|
const skill = loadSkill(skillPath);
|
|
63
70
|
const currentContent = readFileSync(skillPath, "utf-8");
|
|
64
71
|
return {
|
|
65
|
-
content: [
|
|
72
|
+
content: [
|
|
73
|
+
{
|
|
66
74
|
type: "text",
|
|
67
75
|
text: `📋 Skill loaded: ${skill.name}\n` +
|
|
68
76
|
`Path: ${skillPath}\n` +
|
|
@@ -75,15 +83,18 @@ export function createSkillEvolveTool(cfg) {
|
|
|
75
83
|
`3. Use the 'write' tool to save the improved version to: ${skillPath}\n` +
|
|
76
84
|
`4. The new version should be clearer, more concise, and handle more edge cases\n` +
|
|
77
85
|
`(dryRun: ${dryRun ? "enabled — review only, don't write yet" : "disabled — write the improved version"})`,
|
|
78
|
-
}
|
|
86
|
+
},
|
|
87
|
+
],
|
|
79
88
|
};
|
|
80
89
|
}
|
|
81
90
|
catch (err) {
|
|
82
91
|
return {
|
|
83
|
-
content: [
|
|
92
|
+
content: [
|
|
93
|
+
{
|
|
84
94
|
type: "text",
|
|
85
95
|
text: `Error loading skill '${skillName}': ${String(err)}`,
|
|
86
|
-
}
|
|
96
|
+
},
|
|
97
|
+
],
|
|
87
98
|
};
|
|
88
99
|
}
|
|
89
100
|
},
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VPS Security monitoring tool.
|
|
3
|
+
* Monitors fail2ban, UFW, SSH hardening, and honeypot.
|
|
4
|
+
*/
|
|
5
|
+
import type { PoolBotConfig } from "../../config/config.js";
|
|
6
|
+
import type { AnyAgentTool } from "./common.js";
|
|
7
|
+
export declare function createVPSSecurityTool(cfg: PoolBotConfig): AnyAgentTool;
|
|
8
|
+
//# sourceMappingURL=vps-security-tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vps-security-tool.d.ts","sourceRoot":"","sources":["../../../src/agents/tools/vps-security-tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAG5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAKhD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,aAAa,GAAG,YAAY,CAsDtE"}
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VPS Security monitoring tool.
|
|
3
|
+
* Monitors fail2ban, UFW, SSH hardening, and honeypot.
|
|
4
|
+
*/
|
|
5
|
+
import { Type } from "@sinclair/typebox";
|
|
6
|
+
import { exec } from "node:child_process";
|
|
7
|
+
import { promisify } from "node:util";
|
|
8
|
+
import { readStringParam } from "./common.js";
|
|
9
|
+
const execAsync = promisify(exec);
|
|
10
|
+
export function createVPSSecurityTool(cfg) {
|
|
11
|
+
return {
|
|
12
|
+
name: "vps_security",
|
|
13
|
+
label: "VPS Security",
|
|
14
|
+
description: "Monitor and manage VPS security features including fail2ban, UFW firewall, SSH hardening, and honeypot. " +
|
|
15
|
+
"Check security status, view banned IPs, unban IPs, check firewall rules, and generate security reports.",
|
|
16
|
+
parameters: Type.Object({
|
|
17
|
+
action: Type.String({
|
|
18
|
+
description: "Action to perform: 'status', 'fail2ban', 'unban', 'ufw', 'ssh', 'honeypot', 'report'",
|
|
19
|
+
enum: ["status", "fail2ban", "unban", "ufw", "ssh", "honeypot", "report"],
|
|
20
|
+
}),
|
|
21
|
+
ip: Type.Optional(Type.String({
|
|
22
|
+
description: "IP address to unban (required for action='unban')",
|
|
23
|
+
})),
|
|
24
|
+
}),
|
|
25
|
+
execute: async (_toolCallId, args) => {
|
|
26
|
+
const action = readStringParam(args, "action", { required: true });
|
|
27
|
+
const ip = typeof args.ip === "string" ? args.ip : undefined;
|
|
28
|
+
try {
|
|
29
|
+
switch (action) {
|
|
30
|
+
case "status":
|
|
31
|
+
return await checkSecurityStatus();
|
|
32
|
+
case "fail2ban":
|
|
33
|
+
return await checkFail2ban();
|
|
34
|
+
case "unban":
|
|
35
|
+
if (!ip) {
|
|
36
|
+
return errorResult("IP address required for unban action. Use: vps_security(action='unban', ip='1.2.3.4')");
|
|
37
|
+
}
|
|
38
|
+
return await unbanIP(ip);
|
|
39
|
+
case "ufw":
|
|
40
|
+
return await checkUFW();
|
|
41
|
+
case "ssh":
|
|
42
|
+
return await checkSSH();
|
|
43
|
+
case "honeypot":
|
|
44
|
+
return await checkHoneypot();
|
|
45
|
+
case "report":
|
|
46
|
+
return await generateSecurityReport();
|
|
47
|
+
default:
|
|
48
|
+
return errorResult(`Unknown action: ${action}. Valid actions: status, fail2ban, unban, ufw, ssh, honeypot, report`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
return errorResult(`Security command failed: ${String(err)}`);
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
async function runCommand(cmd) {
|
|
58
|
+
const { stdout, stderr } = await execAsync(cmd, { timeout: 30_000 });
|
|
59
|
+
if (stderr && !stderr.includes("warn") && !stderr.includes("deprecated")) {
|
|
60
|
+
throw new Error(stderr);
|
|
61
|
+
}
|
|
62
|
+
return stdout.trim();
|
|
63
|
+
}
|
|
64
|
+
async function checkSecurityStatus() {
|
|
65
|
+
const results = [];
|
|
66
|
+
// fail2ban
|
|
67
|
+
try {
|
|
68
|
+
const f2b = await runCommand("fail2ban-client status sshd 2>/dev/null | head -10");
|
|
69
|
+
const bannedMatch = f2b.match(/Currently banned:\s*(\d+)/);
|
|
70
|
+
const totalBannedMatch = f2b.match(/Total banned:\s*(\d+)/);
|
|
71
|
+
results.push(`✅ fail2ban: Active`);
|
|
72
|
+
if (bannedMatch)
|
|
73
|
+
results.push(` Currently banned: ${bannedMatch[1]} IPs`);
|
|
74
|
+
if (totalBannedMatch)
|
|
75
|
+
results.push(` Total banned: ${totalBannedMatch[1]} IPs`);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
results.push(`❌ fail2ban: Not active`);
|
|
79
|
+
}
|
|
80
|
+
// UFW
|
|
81
|
+
try {
|
|
82
|
+
const ufw = await runCommand("ufw status 2>/dev/null | grep '22.*LIMIT' || echo 'no rate limit'");
|
|
83
|
+
if (ufw.includes("LIMIT")) {
|
|
84
|
+
results.push(`✅ UFW: Active with SSH rate limit`);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
results.push(`⚠️ UFW: Active but no SSH rate limit`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
results.push(`❌ UFW: Not active`);
|
|
92
|
+
}
|
|
93
|
+
// SSH hardening
|
|
94
|
+
try {
|
|
95
|
+
const loginGrace = await runCommand("grep 'LoginGraceTime' /etc/ssh/sshd_config 2>/dev/null | tail -1 || echo 'not set'");
|
|
96
|
+
const maxAuth = await runCommand("grep 'MaxAuthTries' /etc/ssh/sshd_config 2>/dev/null | tail -1 || echo 'not set'");
|
|
97
|
+
results.push(`✅ SSH hardening: ${loginGrace}, ${maxAuth}`);
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
results.push(`⚠️ SSH hardening: Not configured`);
|
|
101
|
+
}
|
|
102
|
+
// Honeypot
|
|
103
|
+
try {
|
|
104
|
+
const hp = await runCommand("pgrep -f 'endlessh -p 2222' && echo 'active' || echo 'inactive'");
|
|
105
|
+
if (hp.includes("active")) {
|
|
106
|
+
results.push(`✅ Honeypot: Active on port 2222`);
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
results.push(`❌ Honeypot: Not active`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
results.push(`❌ Honeypot: Not active`);
|
|
114
|
+
}
|
|
115
|
+
// Calculate score
|
|
116
|
+
let score = 0;
|
|
117
|
+
if (results[0].includes("✅"))
|
|
118
|
+
score += 25;
|
|
119
|
+
if (results[1].includes("✅"))
|
|
120
|
+
score += 25;
|
|
121
|
+
if (results[2].includes("✅"))
|
|
122
|
+
score += 25;
|
|
123
|
+
if (results[3].includes("✅"))
|
|
124
|
+
score += 15;
|
|
125
|
+
score += 10; // Base score
|
|
126
|
+
results.push(`\n📊 Security Score: ${score}/100`);
|
|
127
|
+
return {
|
|
128
|
+
content: [{ type: "text", text: results.join("\n") }],
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
async function checkFail2ban() {
|
|
132
|
+
const output = await runCommand("fail2ban-client status sshd 2>/dev/null");
|
|
133
|
+
const currentlyFailed = output.match(/Currently failed:\s*(\d+)/)?.[1] ?? "0";
|
|
134
|
+
const totalFailed = output.match(/Total failed:\s*(\d+)/)?.[1] ?? "0";
|
|
135
|
+
const currentlyBanned = output.match(/Currently banned:\s*(\d+)/)?.[1] ?? "0";
|
|
136
|
+
const totalBanned = output.match(/Total banned:\s*(\d+)/)?.[1] ?? "0";
|
|
137
|
+
const bannedList = output.match(/Banned IP list:\s*(.*)/)?.[1] ?? "none";
|
|
138
|
+
const text = `🛡️ fail2ban Status (SSH)
|
|
139
|
+
|
|
140
|
+
Currently failed: ${currentlyFailed}
|
|
141
|
+
Total failed: ${totalFailed}
|
|
142
|
+
Currently banned: ${currentlyBanned}
|
|
143
|
+
Total banned: ${totalBanned}
|
|
144
|
+
Banned IPs: ${bannedList}`;
|
|
145
|
+
return {
|
|
146
|
+
content: [{ type: "text", text }],
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
async function unbanIP(ip) {
|
|
150
|
+
// Validate IP format
|
|
151
|
+
const ipRegex = /^(\d{1,3}\.){3}\d{1,3}$/;
|
|
152
|
+
if (!ipRegex.test(ip)) {
|
|
153
|
+
return errorResult(`Invalid IP format: ${ip}. Use format: 1.2.3.4`);
|
|
154
|
+
}
|
|
155
|
+
await runCommand(`fail2ban-client set sshd unbanip ${ip} 2>/dev/null`);
|
|
156
|
+
// Verify unban
|
|
157
|
+
const status = await runCommand("fail2ban-client status sshd 2>/dev/null");
|
|
158
|
+
const stillBanned = status.includes(ip);
|
|
159
|
+
if (stillBanned) {
|
|
160
|
+
return {
|
|
161
|
+
content: [
|
|
162
|
+
{
|
|
163
|
+
type: "text",
|
|
164
|
+
text: `❌ Failed to unban ${ip}. IP may not be banned or fail2ban error.`,
|
|
165
|
+
},
|
|
166
|
+
],
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
return {
|
|
170
|
+
content: [{ type: "text", text: `✅ Successfully unbanned IP: ${ip}` }],
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
async function checkUFW() {
|
|
174
|
+
const output = await runCommand("ufw status verbose 2>/dev/null");
|
|
175
|
+
const activeMatch = output.match(/Status:\s*(\w+)/);
|
|
176
|
+
const status = activeMatch?.[1] ?? "inactive";
|
|
177
|
+
const rules = output
|
|
178
|
+
.split("\n")
|
|
179
|
+
.filter((line) => line.includes("ALLOW") || line.includes("DENY") || line.includes("LIMIT"))
|
|
180
|
+
.slice(0, 20)
|
|
181
|
+
.join("\n");
|
|
182
|
+
const text = `🔥 UFW Firewall Status
|
|
183
|
+
|
|
184
|
+
Status: ${status.toUpperCase()}
|
|
185
|
+
|
|
186
|
+
Rules:
|
|
187
|
+
${rules || "No rules configured"}`;
|
|
188
|
+
return {
|
|
189
|
+
content: [{ type: "text", text }],
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
async function checkSSH() {
|
|
193
|
+
const config = await runCommand("cat /etc/ssh/sshd_config 2>/dev/null");
|
|
194
|
+
const settings = {};
|
|
195
|
+
const keys = [
|
|
196
|
+
"PermitRootLogin",
|
|
197
|
+
"PasswordAuthentication",
|
|
198
|
+
"LoginGraceTime",
|
|
199
|
+
"MaxAuthTries",
|
|
200
|
+
"PubkeyAuthentication",
|
|
201
|
+
];
|
|
202
|
+
for (const key of keys) {
|
|
203
|
+
const match = config.match(new RegExp(`^${key}\\s+(\\w+)`, "m"));
|
|
204
|
+
settings[key] = match?.[1] ?? "not set";
|
|
205
|
+
}
|
|
206
|
+
const text = `🔐 SSH Configuration
|
|
207
|
+
|
|
208
|
+
PermitRootLogin: ${settings.PermitRootLogin}
|
|
209
|
+
PasswordAuthentication: ${settings.PasswordAuthentication}
|
|
210
|
+
LoginGraceTime: ${settings.LoginGraceTime}
|
|
211
|
+
MaxAuthTries: ${settings.MaxAuthTries}
|
|
212
|
+
PubkeyAuthentication: ${settings.PubkeyAuthentication}`;
|
|
213
|
+
return {
|
|
214
|
+
content: [{ type: "text", text }],
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
async function checkHoneypot() {
|
|
218
|
+
const pid = await runCommand("pgrep -f 'endlessh -p 2222' 2>/dev/null || echo 'none'");
|
|
219
|
+
const active = pid !== "none" && pid.trim() !== "";
|
|
220
|
+
const logCount = await runCommand("wc -l < /var/log/endlessh.log 2>/dev/null || echo '0'");
|
|
221
|
+
const text = `🍯 Honeypot (endlessh) Status
|
|
222
|
+
|
|
223
|
+
Status: ${active ? "✅ Active" : "❌ Inactive"}
|
|
224
|
+
Port: 2222
|
|
225
|
+
PID: ${active ? pid.trim() : "N/A"}
|
|
226
|
+
Log entries: ${logCount.trim()}`;
|
|
227
|
+
return {
|
|
228
|
+
content: [{ type: "text", text }],
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
async function generateSecurityReport() {
|
|
232
|
+
const status = await checkSecurityStatus();
|
|
233
|
+
const fail2ban = await checkFail2ban();
|
|
234
|
+
const ufw = await checkUFW();
|
|
235
|
+
const ssh = await checkSSH();
|
|
236
|
+
const honeypot = await checkHoneypot();
|
|
237
|
+
const text = `📊 VPS Security Report
|
|
238
|
+
Generated: ${new Date().toISOString()}
|
|
239
|
+
|
|
240
|
+
${status.content[0].text}
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
${fail2ban.content[0].text}
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
${ufw.content[0].text}
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
${ssh.content[0].text}
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
${honeypot.content[0].text}
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
ℹ️ For detailed documentation, see: docs/security/vps-hardening.md`;
|
|
256
|
+
return {
|
|
257
|
+
content: [{ type: "text", text }],
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
function errorResult(message) {
|
|
261
|
+
return {
|
|
262
|
+
content: [{ type: "text", text: `❌ ${message}` }],
|
|
263
|
+
};
|
|
264
|
+
}
|
package/dist/build-info.json
CHANGED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PoolBot MCP CLI
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* poolbot mcp serve # Start MCP server on stdio (for Claude Desktop)
|
|
6
|
+
* poolbot mcp serve --http # Start MCP server on HTTP (port 3000)
|
|
7
|
+
* poolbot mcp serve --http --port 3001
|
|
8
|
+
*/
|
|
9
|
+
export declare function runMCPCLI(args: string[]): Promise<void>;
|
|
10
|
+
//# sourceMappingURL=mcp-cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-cli.d.ts","sourceRoot":"","sources":["../../src/cli/mcp-cli.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAmC7D"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PoolBot MCP CLI
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* poolbot mcp serve # Start MCP server on stdio (for Claude Desktop)
|
|
6
|
+
* poolbot mcp serve --http # Start MCP server on HTTP (port 3000)
|
|
7
|
+
* poolbot mcp serve --http --port 3001
|
|
8
|
+
*/
|
|
9
|
+
import { runMCPServer } from "../mcp/server.js";
|
|
10
|
+
import { loadConfig } from "../config/config.js";
|
|
11
|
+
import { resolveDefaultAgentId } from "../agents/agent-scope.js";
|
|
12
|
+
export async function runMCPCLI(args) {
|
|
13
|
+
const config = loadConfig();
|
|
14
|
+
const agentId = resolveDefaultAgentId(config);
|
|
15
|
+
const isHTTP = args.includes("--http");
|
|
16
|
+
const portArg = args.find((arg) => arg.startsWith("--port="));
|
|
17
|
+
const port = portArg ? parseInt(portArg.split("=")[1], 10) : undefined;
|
|
18
|
+
const readOnly = args.includes("--read-only");
|
|
19
|
+
console.error("Starting PoolBot MCP Server...");
|
|
20
|
+
console.error(` Agent: ${agentId}`);
|
|
21
|
+
console.error(` Mode: ${isHTTP ? "HTTP" : "stdio"}`);
|
|
22
|
+
if (isHTTP) {
|
|
23
|
+
console.error(` Port: ${port || 3000}`);
|
|
24
|
+
}
|
|
25
|
+
if (readOnly) {
|
|
26
|
+
console.error(" Read-only mode: enabled");
|
|
27
|
+
}
|
|
28
|
+
console.error("");
|
|
29
|
+
console.error("For Claude Desktop, add to claude_desktop_config.json:");
|
|
30
|
+
console.error(JSON.stringify({
|
|
31
|
+
mcpServers: {
|
|
32
|
+
poolbot: {
|
|
33
|
+
command: "poolbot",
|
|
34
|
+
args: ["mcp", "serve"],
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
}, null, 2));
|
|
38
|
+
console.error("");
|
|
39
|
+
await runMCPServer({
|
|
40
|
+
agentId,
|
|
41
|
+
httpPort: port,
|
|
42
|
+
readOnly,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP (Model Context Protocol) Server for PoolBot.
|
|
3
|
+
*
|
|
4
|
+
* Exposes PoolBot sessions and conversations to MCP-compatible clients
|
|
5
|
+
* like Claude Desktop, Cursor, VS Code, etc.
|
|
6
|
+
*
|
|
7
|
+
* Supports both stdio and Streamable HTTP transports.
|
|
8
|
+
*
|
|
9
|
+
* @see https://modelcontextprotocol.io/
|
|
10
|
+
*/
|
|
11
|
+
interface MCPServerOptions {
|
|
12
|
+
agentId?: string;
|
|
13
|
+
workspaceDir?: string;
|
|
14
|
+
httpPort?: number;
|
|
15
|
+
readOnly?: boolean;
|
|
16
|
+
}
|
|
17
|
+
export declare class PoolBotMCPServer {
|
|
18
|
+
private server;
|
|
19
|
+
private options;
|
|
20
|
+
private workspaceDir;
|
|
21
|
+
private agentId;
|
|
22
|
+
constructor(options?: MCPServerOptions);
|
|
23
|
+
private setupHandlers;
|
|
24
|
+
/**
|
|
25
|
+
* Start MCP server with stdio transport (for Claude Desktop, etc.)
|
|
26
|
+
*/
|
|
27
|
+
startStdio(): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* Start MCP server with HTTP transport (for web clients)
|
|
30
|
+
*/
|
|
31
|
+
startHTTP(port?: number): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* Stop the MCP server
|
|
34
|
+
*/
|
|
35
|
+
stop(): Promise<void>;
|
|
36
|
+
}
|
|
37
|
+
export declare function runMCPServer(options?: MCPServerOptions): Promise<void>;
|
|
38
|
+
export {};
|
|
39
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAqBH,UAAU,gBAAgB;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AA0HD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAAmB;IAClC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,OAAO,CAAS;gBAEZ,OAAO,GAAE,gBAAqB;IA2B1C,OAAO,CAAC,aAAa;IAiSrB;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAMjC;;OAEG;IACG,SAAS,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAyB7C;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAG5B;AAID,wBAAsB,YAAY,CAAC,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CA4BhF"}
|