remote-access-mcp 1.0.7 → 2.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 (102) hide show
  1. package/README.fa.md +29 -70
  2. package/README.md +92 -65
  3. package/dist/cli/main.d.ts.map +1 -1
  4. package/dist/cli/main.js +352 -133
  5. package/dist/cli/main.js.map +1 -1
  6. package/dist/core/audit.d.ts +40 -0
  7. package/dist/core/audit.d.ts.map +1 -0
  8. package/dist/core/audit.js +96 -0
  9. package/dist/core/audit.js.map +1 -0
  10. package/dist/core/config.d.ts +37 -5
  11. package/dist/core/config.d.ts.map +1 -1
  12. package/dist/core/config.js +111 -34
  13. package/dist/core/config.js.map +1 -1
  14. package/dist/core/context.d.ts +23 -0
  15. package/dist/core/context.d.ts.map +1 -0
  16. package/dist/core/context.js +32 -0
  17. package/dist/core/context.js.map +1 -0
  18. package/dist/core/crypto.d.ts +6 -0
  19. package/dist/core/crypto.d.ts.map +1 -0
  20. package/dist/core/crypto.js +16 -0
  21. package/dist/core/crypto.js.map +1 -0
  22. package/dist/core/policy.d.ts +19 -0
  23. package/dist/core/policy.d.ts.map +1 -1
  24. package/dist/core/policy.js +57 -0
  25. package/dist/core/policy.js.map +1 -1
  26. package/dist/core/rate-limit.d.ts +14 -0
  27. package/dist/core/rate-limit.d.ts.map +1 -0
  28. package/dist/core/rate-limit.js +67 -0
  29. package/dist/core/rate-limit.js.map +1 -0
  30. package/dist/server/app.d.ts +18 -1
  31. package/dist/server/app.d.ts.map +1 -1
  32. package/dist/server/app.js +119 -25
  33. package/dist/server/app.js.map +1 -1
  34. package/dist/server/run.d.ts +5 -1
  35. package/dist/server/run.d.ts.map +1 -1
  36. package/dist/server/run.js +31 -8
  37. package/dist/server/run.js.map +1 -1
  38. package/dist/tools/filesystem.d.ts +3 -2
  39. package/dist/tools/filesystem.d.ts.map +1 -1
  40. package/dist/tools/filesystem.js +34 -23
  41. package/dist/tools/filesystem.js.map +1 -1
  42. package/dist/tools/git.d.ts +2 -2
  43. package/dist/tools/git.d.ts.map +1 -1
  44. package/dist/tools/git.js +33 -4
  45. package/dist/tools/git.js.map +1 -1
  46. package/dist/tools/http.d.ts +2 -1
  47. package/dist/tools/http.d.ts.map +1 -1
  48. package/dist/tools/http.js +47 -5
  49. package/dist/tools/http.js.map +1 -1
  50. package/dist/tools/index.d.ts +6 -3
  51. package/dist/tools/index.d.ts.map +1 -1
  52. package/dist/tools/index.js +29 -9
  53. package/dist/tools/index.js.map +1 -1
  54. package/dist/tools/logs.d.ts +4 -0
  55. package/dist/tools/logs.d.ts.map +1 -0
  56. package/dist/tools/logs.js +78 -0
  57. package/dist/tools/logs.js.map +1 -0
  58. package/dist/tools/packages.d.ts +4 -0
  59. package/dist/tools/packages.d.ts.map +1 -0
  60. package/dist/tools/packages.js +75 -0
  61. package/dist/tools/packages.js.map +1 -0
  62. package/dist/tools/planning.d.ts +4 -0
  63. package/dist/tools/planning.d.ts.map +1 -0
  64. package/dist/tools/planning.js +118 -0
  65. package/dist/tools/planning.js.map +1 -0
  66. package/dist/tools/policy.d.ts +7 -2
  67. package/dist/tools/policy.d.ts.map +1 -1
  68. package/dist/tools/policy.js +29 -18
  69. package/dist/tools/policy.js.map +1 -1
  70. package/dist/tools/project.d.ts +4 -0
  71. package/dist/tools/project.d.ts.map +1 -0
  72. package/dist/tools/project.js +141 -0
  73. package/dist/tools/project.js.map +1 -0
  74. package/dist/tools/schedule.d.ts +17 -0
  75. package/dist/tools/schedule.d.ts.map +1 -0
  76. package/dist/tools/schedule.js +113 -0
  77. package/dist/tools/schedule.js.map +1 -0
  78. package/dist/tools/security.d.ts +4 -0
  79. package/dist/tools/security.d.ts.map +1 -0
  80. package/dist/tools/security.js +103 -0
  81. package/dist/tools/security.js.map +1 -0
  82. package/dist/tools/services.d.ts +4 -0
  83. package/dist/tools/services.d.ts.map +1 -0
  84. package/dist/tools/services.js +56 -0
  85. package/dist/tools/services.js.map +1 -0
  86. package/dist/tools/shell.d.ts +2 -2
  87. package/dist/tools/shell.d.ts.map +1 -1
  88. package/dist/tools/shell.js +25 -10
  89. package/dist/tools/shell.js.map +1 -1
  90. package/dist/tools/sqlite.d.ts +2 -2
  91. package/dist/tools/sqlite.d.ts.map +1 -1
  92. package/dist/tools/sqlite.js +44 -9
  93. package/dist/tools/sqlite.js.map +1 -1
  94. package/dist/tools/system.d.ts +2 -1
  95. package/dist/tools/system.d.ts.map +1 -1
  96. package/dist/tools/system.js +6 -2
  97. package/dist/tools/system.js.map +1 -1
  98. package/dist/tools/web.d.ts +4 -0
  99. package/dist/tools/web.d.ts.map +1 -0
  100. package/dist/tools/web.js +77 -0
  101. package/dist/tools/web.js.map +1 -0
  102. package/package.json +1 -1
@@ -0,0 +1,103 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { promisify } from 'node:util';
3
+ import fsp from 'node:fs/promises';
4
+ import path from 'node:path';
5
+ import { z } from 'zod';
6
+ import { assertToolPermitted } from '../core/policy.js';
7
+ const exec = promisify(execFile);
8
+ // Patterns that indicate a leaked credential. Deliberately broad —
9
+ // better a false positive the human reviews than a missed live key.
10
+ const SECRET_PATTERNS = [
11
+ ['private key', /-----BEGIN (?:RSA |EC |OPENSSH |PGP )?PRIVATE KEY-----/],
12
+ ['aws access key', /AKIA[0-9A-Z]{16}/],
13
+ ['github token (classic)', /gh[pousr]_[A-Za-z0-9]{20,}/],
14
+ ['github fine-grained token', /github_pat_[A-Za-z0-9_]{20,}/],
15
+ ['slack token', /xox[baprs]-[A-Za-z0-9-]{10,}/],
16
+ ['telegram bot token', /\d{8,10}:AA[A-Za-z0-9_-]{30,}/],
17
+ ['npm token', /npm_[A-Za-z0-9]{30,}/],
18
+ ['google api key', /AIza[0-9A-Za-z_-]{35}/],
19
+ ['generic bearer (long)', /bearer\s+[A-Za-z0-9._-]{40,}/i],
20
+ ['password in connection string', /[a-z+]+:\/\/[^:\s]+:[^@\s]{8,}@/i],
21
+ ];
22
+ const SKIP_DIRS = new Set(['.git', 'node_modules', '.venv', 'venv', '__pycache__', 'dist', 'build', '.next', 'coverage']);
23
+ const TEXT_EXT = /\.(txt|json|ya?ml|toml|ini|env|conf|cfg|js|jsx|ts|tsx|py|rb|go|rs|java|php|sh|bash|sql|md|html|css|xml)$/i;
24
+ export function registerSecurityTools(server, ctx) {
25
+ // ---- secret_scan -----------------------------------------------------------
26
+ server.registerTool('secret_scan', {
27
+ description: 'Scan a directory tree for leaked secrets (private keys, API tokens, passwords). Policy-checked.',
28
+ inputSchema: {
29
+ path: z.string().describe('Directory to scan'),
30
+ max_files: z.number().optional().default(2000).describe('File cap'),
31
+ },
32
+ }, async ({ path: dir, max_files }) => {
33
+ assertToolPermitted({
34
+ tool: 'secret_scan', scopes: ctx.token.scopes, readOnly: ctx.readOnly,
35
+ policy: { allowed_paths: ctx.token.allowed_paths, denied_paths: ctx.token.denied_paths, shell_enabled: ctx.token.shell_enabled },
36
+ target: dir,
37
+ });
38
+ const findings = [];
39
+ let scanned = 0;
40
+ const walk = async (d) => {
41
+ if (scanned >= max_files || findings.length >= 200)
42
+ return;
43
+ let entries;
44
+ try {
45
+ entries = await fsp.readdir(d, { withFileTypes: true });
46
+ }
47
+ catch {
48
+ return;
49
+ }
50
+ for (const e of entries) {
51
+ if (scanned >= max_files)
52
+ return;
53
+ if (e.name.startsWith('.') && e.name !== '.env')
54
+ continue;
55
+ const full = path.join(d, e.name);
56
+ if (e.isDirectory()) {
57
+ if (!SKIP_DIRS.has(e.name))
58
+ await walk(full);
59
+ }
60
+ else if (e.isFile() && TEXT_EXT.test(e.name)) {
61
+ scanned++;
62
+ let content;
63
+ try {
64
+ content = await fsp.readFile(full, 'utf8');
65
+ }
66
+ catch {
67
+ continue;
68
+ }
69
+ const lines = content.split('\n');
70
+ for (let i = 0; i < lines.length; i++) {
71
+ for (const [label, re] of SECRET_PATTERNS) {
72
+ if (re.test(lines[i])) {
73
+ // Mask the actual secret — we only report where it is
74
+ findings.push(`${full}:${i + 1} — possible ${label}`);
75
+ break;
76
+ }
77
+ }
78
+ }
79
+ }
80
+ }
81
+ };
82
+ await walk(dir);
83
+ const summary = findings.length
84
+ ? `Found ${findings.length} potential secret(s) in ${scanned} files:\n${findings.join('\n')}`
85
+ : `Clean: no secrets found in ${scanned} files.`;
86
+ return { content: [{ type: 'text', text: summary }] };
87
+ });
88
+ // ---- port_scan_local ----------------------------------------------------------
89
+ server.registerTool('port_scan_local', {
90
+ description: 'List all listening TCP ports on this host with the owning process (ss -tlnp).',
91
+ inputSchema: {},
92
+ }, async () => {
93
+ assertToolPermitted({ tool: 'port_scan_local', scopes: ctx.token.scopes, readOnly: ctx.readOnly });
94
+ try {
95
+ const { stdout } = await exec('ss', ['-tlnp']);
96
+ return { content: [{ type: 'text', text: stdout }] };
97
+ }
98
+ catch (e) {
99
+ return { content: [{ type: 'text', text: e.message }], isError: true };
100
+ }
101
+ });
102
+ }
103
+ //# sourceMappingURL=security.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.js","sourceRoot":"","sources":["../../src/tools/security.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { ToolContext } from '../core/context.js';
3
+ export declare function registerServiceTools(server: McpServer, ctx: ToolContext): void;
4
+ //# sourceMappingURL=services.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"services.d.ts","sourceRoot":"","sources":["../../src/tools/services.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAUtD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,GAAG,IAAI,CAgD9E"}
@@ -0,0 +1,56 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { promisify } from 'node:util';
3
+ import { z } from 'zod';
4
+ import { assertToolPermitted } from '../core/policy.js';
5
+ const exec = promisify(execFile);
6
+ const MAX = 40_000;
7
+ // Whitelist of actions — anything else would let the AI restart
8
+ // the gateway itself or drop into maintenance targets.
9
+ const SERVICE_ACTIONS = ['start', 'stop', 'restart', 'reload', 'status'];
10
+ const PROTECTED_UNITS = /^(remote-access-mcp|ssh|sshd|systemd|networkd|resolved|dbus|.*\.target)$/;
11
+ export function registerServiceTools(server, ctx) {
12
+ const policy = () => ({
13
+ allowed_paths: ctx.token.allowed_paths,
14
+ denied_paths: ctx.token.denied_paths,
15
+ shell_enabled: ctx.token.shell_enabled,
16
+ });
17
+ // ---- service_status -------------------------------------------------------
18
+ server.registerTool('service_status', {
19
+ description: 'Show whether a systemd unit is active/enabled (safe, read-only, any unit).',
20
+ inputSchema: { unit: z.string().regex(/^[A-Za-z0-9@._\\-]+$/) },
21
+ }, async ({ unit }) => {
22
+ assertToolPermitted({ tool: 'service_status', scopes: ctx.token.scopes, readOnly: ctx.readOnly });
23
+ try {
24
+ const active = await exec('systemctl', ['is-active', unit]);
25
+ const enabled = await exec('systemctl', ['is-enabled', unit]);
26
+ return { content: [{ type: 'text', text: `active: ${active.stdout.trim()}\nenabled: ${enabled.stdout.trim()}` }] };
27
+ }
28
+ catch (e) {
29
+ return { content: [{ type: 'text', text: e.stdout?.trim() || e.message }], isError: true };
30
+ }
31
+ });
32
+ // ---- service_action ----------------------------------------------------------
33
+ server.registerTool('service_action', {
34
+ description: 'Start/stop/restart/reload a systemd service. Protected units (ssh, the gateway itself, targets) are refused.',
35
+ inputSchema: {
36
+ unit: z.string().regex(/^[A-Za-z0-9@._\\-]+$/).describe('Service name, e.g. nginx.service'),
37
+ action: z.enum(SERVICE_ACTIONS).describe('start | stop | restart | reload | status'),
38
+ },
39
+ }, async ({ unit, action }) => {
40
+ assertToolPermitted({ tool: 'service_action', scopes: ctx.token.scopes, readOnly: ctx.readOnly, policy: policy() });
41
+ if (action === 'stop' && PROTECTED_UNITS.test(unit)) {
42
+ return { content: [{ type: 'text', text: `Refusing to ${action} protected unit ${unit}.` }], isError: true };
43
+ }
44
+ if (PROTECTED_UNITS.test(unit)) {
45
+ return { content: [{ type: 'text', text: `Refusing to touch protected unit ${unit}.` }], isError: true };
46
+ }
47
+ try {
48
+ const { stdout, stderr } = await exec('systemctl', [action, unit]);
49
+ return { content: [{ type: 'text', text: `${unit} ${action}: ok\n${stdout || stderr || ''}`.slice(0, MAX) }] };
50
+ }
51
+ catch (e) {
52
+ return { content: [{ type: 'text', text: [e.message, e.stdout, e.stderr].filter(Boolean).join('\n') }], isError: true };
53
+ }
54
+ });
55
+ }
56
+ //# sourceMappingURL=services.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"services.js","sourceRoot":"","sources":["../../src/tools/services.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
1
  import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
- import { PolicyConfig } from '../core/policy.js';
3
- export declare function registerShellTools(server: McpServer, policy: PolicyConfig): void;
2
+ import type { ToolContext } from '../core/context.js';
3
+ export declare function registerShellTools(server: McpServer, ctx: ToolContext): void;
4
4
  //# sourceMappingURL=shell.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"shell.d.ts","sourceRoot":"","sources":["../../src/tools/shell.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,EAAE,YAAY,EAAgB,MAAM,mBAAmB,CAAC;AAM/D,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI,CAoEhF"}
1
+ {"version":3,"file":"shell.d.ts","sourceRoot":"","sources":["../../src/tools/shell.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAOtD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,GAAG,IAAI,CAkF5E"}
@@ -1,28 +1,37 @@
1
1
  import { execFile } from 'node:child_process';
2
2
  import { promisify } from 'node:util';
3
3
  import { z } from 'zod';
4
- import { shellAllowed } from '../core/policy.js';
4
+ import { assertToolPermitted } from '../core/policy.js';
5
5
  const exec = promisify(execFile);
6
6
  const MAX_OUTPUT = 60_000;
7
- export function registerShellTools(server, policy) {
7
+ // Shell injection surface: we run bash -c by design (the tool IS a shell).
8
+ // Guard rails: timeout, output cap, no TTY pty, cwd must exist.
9
+ export function registerShellTools(server, ctx) {
10
+ const policy = () => ({
11
+ allowed_paths: ctx.token.allowed_paths,
12
+ denied_paths: ctx.token.denied_paths,
13
+ shell_enabled: ctx.token.shell_enabled,
14
+ });
8
15
  // ---- run_command -------------------------------------------------------
9
16
  server.registerTool('run_command', {
10
- description: 'Execute a shell command (via bash -c). Disabled unless shell policy is on. 120s timeout.',
17
+ description: 'Execute a shell command (bash -c). Requires shell enabled for this token. 120s default timeout.',
11
18
  inputSchema: {
12
19
  command: z.string().describe('Command line to run'),
13
- cwd: z.string().optional().describe('Working directory'),
20
+ cwd: z.string().optional().describe('Working directory (policy-checked)'),
14
21
  timeout_ms: z.number().optional().default(120_000).describe('Timeout in ms (max 600000)'),
15
22
  },
16
23
  }, async ({ command, cwd, timeout_ms }) => {
17
- if (!shellAllowed(policy)) {
18
- return { content: [{ type: 'text', text: 'Shell execution is disabled. Enable with `ramcp policy shell on`.' }], isError: true };
24
+ if (!ctx.token.shell_enabled) {
25
+ return { content: [{ type: 'text', text: 'Shell execution is disabled for this token. Enable with `ramcp policy shell on` or `ramcp token add --shell`.' }], isError: true };
19
26
  }
27
+ assertToolPermitted({ tool: 'run_command', scopes: ctx.token.scopes, readOnly: ctx.readOnly, policy: policy(), target: cwd });
20
28
  const timeout = Math.min(timeout_ms, 600_000);
21
29
  try {
22
- const { stdout, stderr } = await exec('bash', ['-c', command], {
30
+ const { stdout, stderr } = await exec('bash', ['-lc', command], {
23
31
  cwd: cwd || undefined,
24
32
  timeout,
25
33
  maxBuffer: 10 * 1024 * 1024,
34
+ env: { ...process.env, TERM: 'dumb', LANG: 'C.UTF-8' },
26
35
  });
27
36
  let out = '';
28
37
  if (stdout)
@@ -47,19 +56,25 @@ export function registerShellTools(server, policy) {
47
56
  description: 'List running processes (pid, ppid, user, cpu%, mem%, command). Sorted by CPU.',
48
57
  inputSchema: {},
49
58
  }, async () => {
59
+ assertToolPermitted({ tool: 'process_list', scopes: ctx.token.scopes, readOnly: ctx.readOnly });
50
60
  const { stdout } = await exec('ps', ['axo', 'pid,ppid,user,%cpu,%mem,comm', '--sort=-%cpu']);
51
61
  return { content: [{ type: 'text', text: stdout.slice(0, MAX_OUTPUT) }] };
52
62
  });
53
63
  // ---- kill_process ----------------------------------------------------------
54
64
  server.registerTool('kill_process', {
55
- description: 'Send a signal to a process. Default SIGTERM. Disabled unless shell policy is on.',
65
+ description: 'Send a signal to a process. Requires shell enabled. Cannot kill the gateway itself.',
56
66
  inputSchema: {
57
67
  pid: z.number().describe('Process ID'),
58
68
  signal: z.string().optional().default('SIGTERM').describe('Signal name, e.g. SIGTERM, SIGKILL'),
59
69
  },
60
70
  }, async ({ pid, signal }) => {
61
- if (!shellAllowed(policy)) {
62
- return { content: [{ type: 'text', text: 'Shell execution is disabled. Enable with `ramcp policy shell on`.' }], isError: true };
71
+ if (!ctx.token.shell_enabled) {
72
+ return { content: [{ type: 'text', text: 'Shell execution is disabled for this token.' }], isError: true };
73
+ }
74
+ assertToolPermitted({ tool: 'kill_process', scopes: ctx.token.scopes, readOnly: ctx.readOnly });
75
+ // Guardrail: the AI must not be able to kill the gateway or systemd.
76
+ if (pid === process.pid || pid === 1) {
77
+ return { content: [{ type: 'text', text: `Refusing to signal pid ${pid} (protected).` }], isError: true };
63
78
  }
64
79
  try {
65
80
  process.kill(pid, signal);
@@ -1 +1 @@
1
- {"version":3,"file":"shell.js","sourceRoot":"","sources":["../../src/tools/shell.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"shell.js","sourceRoot":"","sources":["../../src/tools/shell.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
1
  import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
- import { PolicyConfig } from '../core/policy.js';
3
- export declare function registerSqliteTools(server: McpServer, policy: PolicyConfig): void;
2
+ import type { ToolContext } from '../core/context.js';
3
+ export declare function registerSqliteTools(server: McpServer, ctx: ToolContext): void;
4
4
  //# sourceMappingURL=sqlite.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sqlite.d.ts","sourceRoot":"","sources":["../../src/tools/sqlite.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,EAAE,YAAY,EAAiB,MAAM,mBAAmB,CAAC;AAEhE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI,CAwDjF"}
1
+ {"version":3,"file":"sqlite.d.ts","sourceRoot":"","sources":["../../src/tools/sqlite.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAmBtD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,GAAG,IAAI,CAsE7E"}
@@ -1,22 +1,54 @@
1
+ import fs from 'node:fs';
1
2
  import { z } from 'zod';
2
- import { assertAllowed } from '../core/policy.js';
3
- export function registerSqliteTools(server, policy) {
3
+ import { assertToolPermitted } from '../core/policy.js';
4
+ // SQL safety: only one statement per call, and the verb allowlist stops
5
+ // multiple-statement smuggling (better-sqlite3's exec() would run them all).
6
+ const SQL_VERBS = /^(select|with|insert|update|delete|create|drop|alter|pragma|vacuum|analyze|begin|commit|rollback|explain|replace|index|reindex)\b/i;
7
+ function validateSql(sql) {
8
+ const trimmed = sql.trim();
9
+ if (!trimmed)
10
+ return 'empty SQL';
11
+ if (/;/.test(trimmed.slice(0, -1)) && !/pragma/i.test(trimmed))
12
+ return 'multiple statements not allowed';
13
+ const verbMatch = trimmed.match(/^[a-z]+/i);
14
+ if (!verbMatch)
15
+ return 'cannot parse SQL verb';
16
+ // WITH is legal CTE prefix; select/insert/etc. checked directly
17
+ if (!SQL_VERBS.test(verbMatch[0]))
18
+ return `SQL verb "${verbMatch[0]}" not allowed`;
19
+ // Attach/detach can pivot the DB file outside the policy sandbox
20
+ if (/\battach\b|\bdetach\b/i.test(trimmed))
21
+ return 'attach/detach not allowed';
22
+ return null;
23
+ }
24
+ export function registerSqliteTools(server, ctx) {
25
+ const policy = () => ({
26
+ allowed_paths: ctx.token.allowed_paths,
27
+ denied_paths: ctx.token.denied_paths,
28
+ shell_enabled: ctx.token.shell_enabled,
29
+ });
4
30
  // ---- sqlite_query ------------------------------------------------------------------
5
31
  server.registerTool('sqlite_query', {
6
- description: 'Run SQL on a SQLite database file (better-sqlite3, synchronous). Policy-checked.',
32
+ description: 'Run one SQL statement on a SQLite database file. Verb allowlist, single-statement. Policy-checked.',
7
33
  inputSchema: {
8
34
  db_path: z.string().describe('Database file path'),
9
- sql: z.string().describe('SQL statement(s)'),
35
+ sql: z.string().describe('SQL statement'),
10
36
  },
11
37
  }, async ({ db_path, sql }) => {
12
- assertAllowed(policy, db_path);
38
+ assertToolPermitted({ tool: 'sqlite_query', scopes: ctx.token.scopes, readOnly: ctx.readOnly, policy: policy(), target: db_path });
39
+ const err = validateSql(sql);
40
+ if (err)
41
+ return { content: [{ type: 'text', text: `SQL rejected: ${err}` }], isError: true };
42
+ if (!fs.existsSync(db_path)) {
43
+ return { content: [{ type: 'text', text: `No such database: ${db_path}` }], isError: true };
44
+ }
13
45
  try {
14
46
  const { default: Database } = await import('better-sqlite3');
15
- const db = new Database(db_path, { readonly: false, fileMustExist: true });
47
+ const db = new Database(db_path, { fileMustExist: true });
16
48
  try {
17
49
  const trimmed = sql.trim().toLowerCase();
18
- const isSelect = trimmed.startsWith('select') || trimmed.startsWith('with') || trimmed.startsWith('pragma');
19
- if (isSelect) {
50
+ const readOnlyVerb = trimmed.startsWith('select') || trimmed.startsWith('with') || trimmed.startsWith('pragma') || trimmed.startsWith('explain');
51
+ if (readOnlyVerb) {
20
52
  const rows = db.prepare(sql).all();
21
53
  return { content: [{ type: 'text', text: JSON.stringify(rows, null, 2).slice(0, 60_000) || '[]' }] };
22
54
  }
@@ -36,7 +68,10 @@ export function registerSqliteTools(server, policy) {
36
68
  description: 'List tables and their CREATE statements for a SQLite database. Policy-checked.',
37
69
  inputSchema: { db_path: z.string().describe('Database file path') },
38
70
  }, async ({ db_path }) => {
39
- assertAllowed(policy, db_path);
71
+ assertToolPermitted({ tool: 'sqlite_schema', scopes: ctx.token.scopes, readOnly: ctx.readOnly, policy: policy(), target: db_path });
72
+ if (!fs.existsSync(db_path)) {
73
+ return { content: [{ type: 'text', text: `No such database: ${db_path}` }], isError: true };
74
+ }
40
75
  try {
41
76
  const { default: Database } = await import('better-sqlite3');
42
77
  const db = new Database(db_path, { readonly: true, fileMustExist: true });
@@ -1 +1 @@
1
- {"version":3,"file":"sqlite.js","sourceRoot":"","sources":["../../src/tools/sqlite.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sqlite.js","sourceRoot":"","sources":["../../src/tools/sqlite.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
1
  import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
- export declare function registerSystemTools(server: McpServer): void;
2
+ import type { ToolContext } from '../core/context.js';
3
+ export declare function registerSystemTools(server: McpServer, ctx: ToolContext): void;
3
4
  //# sourceMappingURL=system.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"system.d.ts","sourceRoot":"","sources":["../../src/tools/system.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIzE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAuD3D"}
1
+ {"version":3,"file":"system.d.ts","sourceRoot":"","sources":["../../src/tools/system.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAItD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,GAAG,IAAI,CA0D7E"}
@@ -2,13 +2,15 @@ import os from 'node:os';
2
2
  import { execFile } from 'node:child_process';
3
3
  import { promisify } from 'node:util';
4
4
  import { z } from 'zod';
5
+ import { assertToolPermitted } from '../core/policy.js';
5
6
  const exec = promisify(execFile);
6
- export function registerSystemTools(server) {
7
+ export function registerSystemTools(server, ctx) {
7
8
  // ---- system_info ---------------------------------------------------------
8
9
  server.registerTool('system_info', {
9
10
  description: 'Host, platform, CPU, memory, uptime, and Node.js version of the server.',
10
11
  inputSchema: {},
11
12
  }, async () => {
13
+ assertToolPermitted({ tool: 'system_info', scopes: ctx.token.scopes, readOnly: ctx.readOnly });
12
14
  const cpus = os.cpus();
13
15
  const out = [
14
16
  `hostname: ${os.hostname()}`,
@@ -24,9 +26,10 @@ export function registerSystemTools(server) {
24
26
  });
25
27
  // ---- disk_usage ------------------------------------------------------------
26
28
  server.registerTool('disk_usage', {
27
- description: 'Filesystem sizes and usage. Human-readable df output plus inodes.',
29
+ description: 'Filesystem sizes and usage. Human-readable df output.',
28
30
  inputSchema: { path: z.string().optional().describe('Restrict to a mount point') },
29
31
  }, async ({ path }) => {
32
+ assertToolPermitted({ tool: 'disk_usage', scopes: ctx.token.scopes, readOnly: ctx.readOnly });
30
33
  const args = ['-h'];
31
34
  if (path)
32
35
  args.push(path);
@@ -43,6 +46,7 @@ export function registerSystemTools(server) {
43
46
  description: 'List network interfaces with addresses. Loopback included.',
44
47
  inputSchema: {},
45
48
  }, async () => {
49
+ assertToolPermitted({ tool: 'network_interfaces', scopes: ctx.token.scopes, readOnly: ctx.readOnly });
46
50
  const ifaces = os.networkInterfaces();
47
51
  const lines = [];
48
52
  for (const [name, addrs] of Object.entries(ifaces)) {
@@ -1 +1 @@
1
- {"version":3,"file":"system.js","sourceRoot":"","sources":["../../src/tools/system.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"system.js","sourceRoot":"","sources":["../../src/tools/system.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { ToolContext } from '../core/context.js';
3
+ export declare function registerWebTools(server: McpServer, ctx: ToolContext): void;
4
+ //# sourceMappingURL=web.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web.d.ts","sourceRoot":"","sources":["../../src/tools/web.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAqCtD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,GAAG,IAAI,CAmC1E"}
@@ -0,0 +1,77 @@
1
+ import { z } from 'zod';
2
+ import { assertToolPermitted } from '../core/policy.js';
3
+ const MAX_BODY = 512 * 1024;
4
+ // SSRF guard: refuse requests to loopback/link-local/metadata addresses
5
+ // unless explicitly allowed. The gateway itself listens on loopback —
6
+ // an AI must not be able to bypass auth by fetching its own endpoint
7
+ // from inside, or hit cloud metadata services.
8
+ import net from 'node:net';
9
+ function isBlockedHost(hostname) {
10
+ // IPv4 literals
11
+ if (net.isIPv4(hostname)) {
12
+ const parts = hostname.split('.').map(Number);
13
+ const [a, b] = parts;
14
+ if (a === 127 || a === 10)
15
+ return true;
16
+ if (a === 172 && b >= 16 && b <= 31)
17
+ return true;
18
+ if (a === 192 && b === 168)
19
+ return true;
20
+ if (a === 169 && b === 254)
21
+ return true; // link-local incl. cloud metadata
22
+ if (a === 0)
23
+ return true;
24
+ return false;
25
+ }
26
+ // IPv6 literals
27
+ if (net.isIPv6(hostname)) {
28
+ const h = hostname.toLowerCase();
29
+ if (h === '::1' || h === '::' || h.startsWith('fe80') || h.startsWith('fc') || h.startsWith('fd'))
30
+ return true;
31
+ // IPv4-mapped
32
+ const m = h.match(/::ffff:(\d+\.\d+\.\d+\.\d+)$/);
33
+ if (m)
34
+ return isBlockedHost(m[1]);
35
+ return false;
36
+ }
37
+ // Hostnames that resolve to private ranges are checked at connect time
38
+ // by fetch itself — but block the obvious ones textually:
39
+ const blockedNames = ['metadata.google.internal', 'instance-data', 'localhost'];
40
+ return blockedNames.some(n => hostname === n || hostname.endsWith('.' + n));
41
+ }
42
+ export function registerWebTools(server, ctx) {
43
+ // ---- web_fetch ---------------------------------------------------------------
44
+ server.registerTool('web_fetch', {
45
+ description: 'Fetch a URL and return the response body (text, truncated). SSRF-guarded: private/metadata ranges are refused.',
46
+ inputSchema: {
47
+ url: z.string().url().describe('Public URL to fetch'),
48
+ max_bytes: z.number().optional().default(100_000).describe('Max body bytes'),
49
+ },
50
+ }, async ({ url, max_bytes }) => {
51
+ assertToolPermitted({ tool: 'web_fetch', scopes: ctx.token.scopes, readOnly: ctx.readOnly });
52
+ const parsed = new URL(url);
53
+ if (!['http:', 'https:'].includes(parsed.protocol)) {
54
+ return { content: [{ type: 'text', text: `Protocol ${parsed.protocol} not allowed.` }], isError: true };
55
+ }
56
+ if (isBlockedHost(parsed.hostname)) {
57
+ return { content: [{ type: 'text', text: `Refusing to fetch internal/private host ${parsed.hostname}.` }], isError: true };
58
+ }
59
+ try {
60
+ const controller = new AbortController();
61
+ const timer = setTimeout(() => controller.abort(), 20_000);
62
+ const resp = await fetch(url, {
63
+ redirect: 'follow',
64
+ signal: controller.signal,
65
+ headers: { 'User-Agent': 'remote-access-mcp/2.0 (+https://github.com/AmirAliManzar/remote-access-mcp)' },
66
+ });
67
+ clearTimeout(timer);
68
+ const text = (await resp.text()).slice(0, Math.min(max_bytes, MAX_BODY));
69
+ const head = `status: ${resp.status} ${resp.statusText}\ncontent-type: ${resp.headers.get('content-type') || '?'}\n\n`;
70
+ return { content: [{ type: 'text', text: head + text }] };
71
+ }
72
+ catch (e) {
73
+ return { content: [{ type: 'text', text: `fetch failed: ${e.message}` }], isError: true };
74
+ }
75
+ });
76
+ }
77
+ //# sourceMappingURL=web.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/tools/web.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "remote-access-mcp",
3
- "version": "1.0.7",
3
+ "version": "2.0.0",
4
4
  "description": "Turn any Linux server into an AI-agent-accessible machine via MCP. ChatGPT, Claude, and Grok connect over HTTPS and control files, shell, git, and more — securely and with zero Python dependencies.",
5
5
  "type": "module",
6
6
  "bin": {