@wunderio/wdrmcp 0.1.10 → 0.1.12
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/README.md +20 -6
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +40 -7
- package/dist/config.js.map +1 -1
- package/dist/executors/command.d.ts +13 -4
- package/dist/executors/command.d.ts.map +1 -1
- package/dist/executors/command.js +94 -18
- package/dist/executors/command.js.map +1 -1
- package/dist/executors/mcp-proxy.d.ts +22 -5
- package/dist/executors/mcp-proxy.d.ts.map +1 -1
- package/dist/executors/mcp-proxy.js +163 -29
- package/dist/executors/mcp-proxy.js.map +1 -1
- package/dist/executors/ssh.d.ts +6 -1
- package/dist/executors/ssh.d.ts.map +1 -1
- package/dist/executors/ssh.js +36 -20
- package/dist/executors/ssh.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts +4 -2
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +8 -3
- package/dist/logger.js.map +1 -1
- package/dist/registry.d.ts +1 -0
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +141 -17
- package/dist/registry.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +16 -8
- package/dist/server.js.map +1 -1
- package/dist/types.d.ts +15 -3
- package/dist/types.d.ts.map +1 -1
- package/package.json +6 -5
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ Built with the [official MCP TypeScript SDK](https://github.com/modelcontextprot
|
|
|
8
8
|
|
|
9
9
|
- **YAML-driven tool definitions** — define tools declaratively, no code changes needed
|
|
10
10
|
- **Docker container execution** — run commands in Docker containers with security validation
|
|
11
|
-
- **MCP server proxying** — proxy tool calls to remote MCP servers via HTTP JSON-RPC
|
|
11
|
+
- **MCP server proxying** — proxy tool calls to remote MCP servers via HTTP JSON-RPC / Streamable HTTP MCP
|
|
12
12
|
- **Dynamic tool discovery** — automatically fetch and expose tools from remote MCP servers
|
|
13
13
|
- **Security** — container ownership validation, command injection prevention, argument validation
|
|
14
14
|
- **DDEV integration** — built-in support for DDEV container naming and project scoping
|
|
@@ -40,6 +40,7 @@ wdrmcp --tools-config /path/to/tools-config [options]
|
|
|
40
40
|
| `--tools-config <path>` | Path to YAML tool config directory | *(required)* |
|
|
41
41
|
| `--log-level <level>` | Log level (debug, info, warn, error) | `info` |
|
|
42
42
|
| `--log-file <path>` | Log file path | `/tmp/wdrmcp.log` |
|
|
43
|
+
| `--strict-host-key-checking` | Enforce SSH host key verification | `false` |
|
|
43
44
|
|
|
44
45
|
**Environment variables:**
|
|
45
46
|
|
|
@@ -48,6 +49,7 @@ wdrmcp --tools-config /path/to/tools-config [options]
|
|
|
48
49
|
| `DDEV_PROJECT` | DDEV project name | `default-project` |
|
|
49
50
|
| `HOST_PROJECT_ROOT` | Host filesystem project root | `/workspace` |
|
|
50
51
|
| `CONTAINER_PROJECT_ROOT` | Container filesystem project root | `/var/www/html` |
|
|
52
|
+
| `SSH_STRICT_HOST_KEY_CHECKING` | Enforce SSH host key verification (`true`/`false`) | `false` |
|
|
51
53
|
|
|
52
54
|
### VS Code / GitHub Copilot Configuration
|
|
53
55
|
|
|
@@ -71,7 +73,7 @@ Tools are defined in YAML files within the tools-config directory. Each file mus
|
|
|
71
73
|
|
|
72
74
|
### Command Tool
|
|
73
75
|
|
|
74
|
-
Executes shell commands
|
|
76
|
+
Executes shell commands over SSH:
|
|
75
77
|
|
|
76
78
|
```yaml
|
|
77
79
|
tools:
|
|
@@ -80,8 +82,9 @@ tools:
|
|
|
80
82
|
description: "What this tool does"
|
|
81
83
|
type: command
|
|
82
84
|
command_template: "my-command {arg1} {arg2}"
|
|
83
|
-
|
|
84
|
-
|
|
85
|
+
ssh_target: "web"
|
|
86
|
+
ssh_user: "${DDEV_SSH_USER}"
|
|
87
|
+
working_dir: "/var/www/html"
|
|
85
88
|
shell: "/bin/bash"
|
|
86
89
|
default_args:
|
|
87
90
|
arg2: "default-value"
|
|
@@ -91,6 +94,7 @@ tools:
|
|
|
91
94
|
validation_rules:
|
|
92
95
|
- pattern: "dangerous-pattern"
|
|
93
96
|
message: "This pattern is not allowed"
|
|
97
|
+
max_arg_length: 4096
|
|
94
98
|
input_schema:
|
|
95
99
|
type: object
|
|
96
100
|
properties:
|
|
@@ -115,10 +119,13 @@ tools:
|
|
|
115
119
|
expose_remote_tools: true
|
|
116
120
|
tool_prefix: "remote_"
|
|
117
121
|
timeout: 30
|
|
118
|
-
auth_token: "
|
|
119
|
-
verify_ssl: true
|
|
122
|
+
auth_token: "${REMOTE_MCP_TOKEN}"
|
|
120
123
|
```
|
|
121
124
|
|
|
125
|
+
Notes:
|
|
126
|
+
- `wdrmcp` supports both plain JSON-RPC HTTP MCP endpoints and Streamable HTTP MCP endpoints.
|
|
127
|
+
- For Streamable HTTP servers, `wdrmcp` performs `initialize` and `notifications/initialized`, keeps `mcp-session-id`, and sends `Accept: application/json, text/event-stream`.
|
|
128
|
+
|
|
122
129
|
## Architecture
|
|
123
130
|
|
|
124
131
|
```
|
|
@@ -139,3 +146,10 @@ src/
|
|
|
139
146
|
## License
|
|
140
147
|
|
|
141
148
|
MIT
|
|
149
|
+
|
|
150
|
+
## Security Notes
|
|
151
|
+
|
|
152
|
+
- Argument placeholders in `command_template` are shell-escaped per argument before execution.
|
|
153
|
+
- `disallowed_commands` are matched against both argument values and rendered command strings.
|
|
154
|
+
- Host key verification is configurable; set `--strict-host-key-checking` (or `SSH_STRICT_HOST_KEY_CHECKING=true`) for production-like environments.
|
|
155
|
+
- Use environment placeholders for credentials (`${VAR}`) instead of literal secrets in YAML.
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AA4D/C,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,YAAY,CA2EtD"}
|
package/dist/config.js
CHANGED
|
@@ -2,21 +2,38 @@
|
|
|
2
2
|
* CLI argument parsing and configuration loading.
|
|
3
3
|
*/
|
|
4
4
|
import { existsSync, readFileSync } from "node:fs";
|
|
5
|
-
|
|
5
|
+
import { resolve } from "node:path";
|
|
6
|
+
import dotenv from "dotenv";
|
|
7
|
+
const DEFAULT_SSH_USER_FILE = "/workspace/.ddev/.agents/.runtime.env";
|
|
6
8
|
function readSshUserFromFile(filePath) {
|
|
7
9
|
if (!existsSync(filePath)) {
|
|
8
10
|
return undefined;
|
|
9
11
|
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
try {
|
|
13
|
+
const raw = readFileSync(filePath, "utf-8");
|
|
14
|
+
for (const line of raw.split("\n")) {
|
|
15
|
+
const trimmed = line.trim();
|
|
16
|
+
if (trimmed.startsWith("DDEV_SSH_USER=")) {
|
|
17
|
+
const value = trimmed.slice("DDEV_SSH_USER=".length).trim();
|
|
18
|
+
return value || undefined;
|
|
19
|
+
}
|
|
16
20
|
}
|
|
17
21
|
}
|
|
22
|
+
catch {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
18
25
|
return undefined;
|
|
19
26
|
}
|
|
27
|
+
function loadEnvFileIfExists(filePath) {
|
|
28
|
+
if (!existsSync(filePath)) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
dotenv.config({ path: filePath, override: false });
|
|
32
|
+
}
|
|
33
|
+
function loadProjectEnvFromToolsConfigPath(toolsConfigPath) {
|
|
34
|
+
const toolsConfigEnv = resolve(toolsConfigPath, ".env");
|
|
35
|
+
loadEnvFileIfExists(toolsConfigEnv);
|
|
36
|
+
}
|
|
20
37
|
function printUsage() {
|
|
21
38
|
console.error(`
|
|
22
39
|
Usage: wdrmcp --tools-config <path> [options]
|
|
@@ -25,6 +42,8 @@ Options:
|
|
|
25
42
|
--tools-config <path> Path to directory containing YAML tool configuration files (required)
|
|
26
43
|
--log-level <level> Log level: debug, info, warn, error (default: info)
|
|
27
44
|
--log-file <path> Path to log file (default: /tmp/wdrmcp.log)
|
|
45
|
+
--strict-host-key-checking Enforce SSH host key verification (default: false)
|
|
46
|
+
--verbose Enable extensive logging (full outputs, command details, debug info)
|
|
28
47
|
--help Show this help message
|
|
29
48
|
|
|
30
49
|
Environment variables:
|
|
@@ -34,6 +53,7 @@ Environment variables:
|
|
|
34
53
|
DDEV_SSH_USER SSH user for container connections (preferred)
|
|
35
54
|
DDEV_SSH_USER_FILE Path to a file containing SSH user (fallback)
|
|
36
55
|
SSH_USER SSH user for container connections (fallback, default: $USER)
|
|
56
|
+
SSH_STRICT_HOST_KEY_CHECKING true/false toggle for SSH host key checking
|
|
37
57
|
`);
|
|
38
58
|
}
|
|
39
59
|
export function parseArgs(argv) {
|
|
@@ -41,6 +61,8 @@ export function parseArgs(argv) {
|
|
|
41
61
|
let toolsConfigPath;
|
|
42
62
|
let logLevel = "info";
|
|
43
63
|
let logFile = "/tmp/wdrmcp.log";
|
|
64
|
+
let verboseLogging = false;
|
|
65
|
+
let strictHostKeyChecking = (process.env.SSH_STRICT_HOST_KEY_CHECKING ?? "false").toLowerCase() === "true";
|
|
44
66
|
for (let i = 0; i < args.length; i++) {
|
|
45
67
|
switch (args[i]) {
|
|
46
68
|
case "--tools-config":
|
|
@@ -52,6 +74,12 @@ export function parseArgs(argv) {
|
|
|
52
74
|
case "--log-file":
|
|
53
75
|
logFile = args[++i];
|
|
54
76
|
break;
|
|
77
|
+
case "--verbose":
|
|
78
|
+
verboseLogging = true;
|
|
79
|
+
break;
|
|
80
|
+
case "--strict-host-key-checking":
|
|
81
|
+
strictHostKeyChecking = true;
|
|
82
|
+
break;
|
|
55
83
|
case "--help":
|
|
56
84
|
printUsage();
|
|
57
85
|
process.exit(0);
|
|
@@ -66,6 +94,9 @@ export function parseArgs(argv) {
|
|
|
66
94
|
printUsage();
|
|
67
95
|
process.exit(1);
|
|
68
96
|
}
|
|
97
|
+
// Load project .env early so placeholders in tools config can resolve
|
|
98
|
+
// without requiring shell-level exports.
|
|
99
|
+
loadProjectEnvFromToolsConfigPath(toolsConfigPath);
|
|
69
100
|
// SSH user resolution strategy:
|
|
70
101
|
// 1. Primary: DDEV_SSH_USER env var (explicit override)
|
|
71
102
|
// 2. Secondary: Read from .env file (auto-detected in container)
|
|
@@ -83,9 +114,11 @@ export function parseArgs(argv) {
|
|
|
83
114
|
ddevProject: process.env.DDEV_PROJECT ?? "default-project",
|
|
84
115
|
logLevel,
|
|
85
116
|
logFile,
|
|
117
|
+
verboseLogging,
|
|
86
118
|
hostProjectRoot: process.env.HOST_PROJECT_ROOT ?? "/workspace",
|
|
87
119
|
containerProjectRoot: process.env.CONTAINER_PROJECT_ROOT ?? "/var/www/html",
|
|
88
120
|
sshUser,
|
|
121
|
+
strictHostKeyChecking,
|
|
89
122
|
};
|
|
90
123
|
}
|
|
91
124
|
//# sourceMappingURL=config.js.map
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* CommandToolExecutor — executes shell commands via SSH
|
|
3
3
|
* with argument substitution ({placeholder} syntax).
|
|
4
4
|
*/
|
|
5
|
-
import type { ToolExecutionResult, ToolExecutor, ValidationRule, ContainerExecutor } from "../types.js";
|
|
5
|
+
import type { ToolExecutionResult, ToolExecutor, ValidationRule, DisallowedCommand, ContainerExecutor } from "../types.js";
|
|
6
6
|
export interface CommandExecutorOptions {
|
|
7
7
|
commandTemplate: string;
|
|
8
8
|
host: string;
|
|
@@ -10,9 +10,10 @@ export interface CommandExecutorOptions {
|
|
|
10
10
|
sshUser?: string;
|
|
11
11
|
shell?: string;
|
|
12
12
|
workingDir?: string;
|
|
13
|
-
defaultArgs?: Record<string, string>;
|
|
14
|
-
disallowedCommands?: string[];
|
|
13
|
+
defaultArgs?: Record<string, string | string[]>;
|
|
14
|
+
disallowedCommands?: (string | DisallowedCommand)[];
|
|
15
15
|
validationRules?: ValidationRule[];
|
|
16
|
+
maxArgLength?: number;
|
|
16
17
|
}
|
|
17
18
|
export declare class CommandToolExecutor implements ToolExecutor {
|
|
18
19
|
private readonly commandTemplate;
|
|
@@ -24,10 +25,18 @@ export declare class CommandToolExecutor implements ToolExecutor {
|
|
|
24
25
|
private readonly defaultArgs;
|
|
25
26
|
private readonly disallowedCommands;
|
|
26
27
|
private readonly validationRules;
|
|
28
|
+
private readonly maxArgLength;
|
|
27
29
|
constructor(options: CommandExecutorOptions);
|
|
28
30
|
execute(args: Record<string, unknown>): Promise<ToolExecutionResult>;
|
|
29
31
|
validateArguments(args: Record<string, unknown>): void;
|
|
30
|
-
/**
|
|
32
|
+
/**
|
|
33
|
+
* Check validation rules against a value. Returns error message or null.
|
|
34
|
+
* When fieldName is provided, only rules targeting that field (or all fields) apply.
|
|
35
|
+
* When fieldName is omitted (rendered command check), only non-field-specific rules apply.
|
|
36
|
+
*/
|
|
31
37
|
private checkRules;
|
|
38
|
+
private escapeShellArg;
|
|
39
|
+
private matchesDisallowed;
|
|
40
|
+
private formatBlockedMessage;
|
|
32
41
|
}
|
|
33
42
|
//# sourceMappingURL=command.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../src/executors/command.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,mBAAmB,EAAE,YAAY,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../src/executors/command.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,mBAAmB,EAAE,YAAY,EAAE,cAAc,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAE3H,MAAM,WAAW,sBAAsB;IACrC,eAAe,EAAE,MAAM,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAChD,kBAAkB,CAAC,EAAE,CAAC,MAAM,GAAG,iBAAiB,CAAC,EAAE,CAAC;IACpD,eAAe,CAAC,EAAE,cAAc,EAAE,CAAC;IACnC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,qBAAa,mBAAoB,YAAW,YAAY;IACtD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAoB;IAC7C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAoC;IAChE,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAsB;IACzD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAmB;IACnD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;gBAE1B,OAAO,EAAE,sBAAsB;IAerC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAoG1E,iBAAiB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IA+BtD;;;;OAIG;IACH,OAAO,CAAC,UAAU;IAclB,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,iBAAiB;IAczB,OAAO,CAAC,oBAAoB;CAM7B"}
|
|
@@ -13,6 +13,7 @@ export class CommandToolExecutor {
|
|
|
13
13
|
defaultArgs;
|
|
14
14
|
disallowedCommands;
|
|
15
15
|
validationRules;
|
|
16
|
+
maxArgLength;
|
|
16
17
|
constructor(options) {
|
|
17
18
|
this.commandTemplate = options.commandTemplate;
|
|
18
19
|
this.host = options.host;
|
|
@@ -21,30 +22,55 @@ export class CommandToolExecutor {
|
|
|
21
22
|
this.shell = options.shell ?? "/bin/bash";
|
|
22
23
|
this.workingDir = options.workingDir;
|
|
23
24
|
this.defaultArgs = options.defaultArgs ?? {};
|
|
24
|
-
this.disallowedCommands =
|
|
25
|
+
this.disallowedCommands = (options.disallowedCommands ?? []).map((d) => typeof d === "string" ? { pattern: d } : d);
|
|
25
26
|
this.validationRules = options.validationRules ?? [];
|
|
27
|
+
this.maxArgLength = options.maxArgLength ?? 4096;
|
|
26
28
|
}
|
|
27
29
|
async execute(args) {
|
|
28
30
|
const log = getLogger();
|
|
29
31
|
const startTime = Date.now();
|
|
30
32
|
// Merge with defaults.
|
|
31
33
|
const mergedArgs = { ...this.defaultArgs, ...args };
|
|
32
|
-
log.
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
if (log.isVerbose()) {
|
|
35
|
+
log.debug(`Executing with args:`, mergedArgs);
|
|
36
|
+
}
|
|
37
|
+
// Check disallowed patterns against all provided string arguments.
|
|
38
|
+
for (const value of Object.values(mergedArgs)) {
|
|
39
|
+
const strings = Array.isArray(value)
|
|
40
|
+
? value.filter((v) => typeof v === "string")
|
|
41
|
+
: typeof value === "string" ? [value] : [];
|
|
42
|
+
for (const str of strings) {
|
|
43
|
+
const blocked = this.matchesDisallowed(str);
|
|
44
|
+
if (blocked) {
|
|
45
|
+
log.warn(`Blocked disallowed command in arguments`);
|
|
46
|
+
return { content: this.formatBlockedMessage(blocked), isError: true };
|
|
47
|
+
}
|
|
48
|
+
}
|
|
37
49
|
}
|
|
38
50
|
// Substitute arguments into template.
|
|
39
51
|
let cmdStr;
|
|
40
52
|
try {
|
|
41
|
-
log.
|
|
53
|
+
if (log.isVerbose()) {
|
|
54
|
+
log.debug(`Command template: ${this.commandTemplate}`);
|
|
55
|
+
}
|
|
42
56
|
cmdStr = this.commandTemplate.replace(/\{(\w+)\}/g, (_match, key) => {
|
|
43
|
-
if (key in mergedArgs)
|
|
44
|
-
|
|
57
|
+
if (key in mergedArgs) {
|
|
58
|
+
const raw = mergedArgs[key];
|
|
59
|
+
// Array values: escape each element individually, join with spaces.
|
|
60
|
+
if (Array.isArray(raw)) {
|
|
61
|
+
const parts = raw.map(String).filter(Boolean);
|
|
62
|
+
return parts.map((p) => this.escapeShellArg(p)).join(" ");
|
|
63
|
+
}
|
|
64
|
+
const val = String(raw);
|
|
65
|
+
return val === "" ? "" : this.escapeShellArg(val);
|
|
66
|
+
}
|
|
45
67
|
throw new Error(`Missing required argument: ${key}`);
|
|
46
68
|
});
|
|
47
|
-
|
|
69
|
+
// Collapse extra whitespace left by empty placeholders.
|
|
70
|
+
cmdStr = cmdStr.replace(/ +/g, " ").trim();
|
|
71
|
+
if (log.isVerbose()) {
|
|
72
|
+
log.debug(`Rendered command: ${cmdStr}`);
|
|
73
|
+
}
|
|
48
74
|
}
|
|
49
75
|
catch (e) {
|
|
50
76
|
log.warn(`Argument substitution failed: ${e.message}`);
|
|
@@ -56,6 +82,11 @@ export class CommandToolExecutor {
|
|
|
56
82
|
log.warn(`Validation failed: ${ruleError}`);
|
|
57
83
|
return { content: `Validation error: ${ruleError}`, isError: true };
|
|
58
84
|
}
|
|
85
|
+
const blocked = this.matchesDisallowed(cmdStr);
|
|
86
|
+
if (blocked) {
|
|
87
|
+
log.warn(`Blocked disallowed command in rendered template`);
|
|
88
|
+
return { content: this.formatBlockedMessage(blocked), isError: true };
|
|
89
|
+
}
|
|
59
90
|
// Execute via injected executor (SSH or other).
|
|
60
91
|
try {
|
|
61
92
|
log.info(`EXEC: ${this.host} via ${this.executor.constructor.name}, shell: ${this.shell}, workdir: ${this.workingDir || "default"}`);
|
|
@@ -79,18 +110,31 @@ export class CommandToolExecutor {
|
|
|
79
110
|
const duration = Date.now() - startTime;
|
|
80
111
|
const errorMsg = e.message;
|
|
81
112
|
log.error(`EXEC FAILED: ${this.host} (${duration}ms), error: ${errorMsg}`);
|
|
82
|
-
log.
|
|
113
|
+
if (log.isVerbose()) {
|
|
114
|
+
log.debug(`Failed command: ${cmdStr}`);
|
|
115
|
+
}
|
|
83
116
|
return {
|
|
84
|
-
content: `Command failed: ${
|
|
117
|
+
content: `Command failed: ${errorMsg}`,
|
|
85
118
|
isError: true
|
|
86
119
|
};
|
|
87
120
|
}
|
|
88
121
|
}
|
|
89
122
|
validateArguments(args) {
|
|
90
|
-
// Check validation rules against
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
123
|
+
// Check validation rules and max-length against each string argument value.
|
|
124
|
+
for (const [key, value] of Object.entries(args)) {
|
|
125
|
+
const strings = Array.isArray(value)
|
|
126
|
+
? value.filter((v) => typeof v === "string")
|
|
127
|
+
: typeof value === "string" ? [value] : [];
|
|
128
|
+
for (const str of strings) {
|
|
129
|
+
if (str.length > this.maxArgLength) {
|
|
130
|
+
throw new Error(`Argument '${key}' exceeds max length of ${this.maxArgLength}`);
|
|
131
|
+
}
|
|
132
|
+
const ruleError = this.checkRules(str, key);
|
|
133
|
+
if (ruleError) {
|
|
134
|
+
throw new Error(ruleError);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
94
138
|
// Verify required placeholders are provided.
|
|
95
139
|
const placeholders = new Set([...this.commandTemplate.matchAll(/\{(\w+)\}/g)].map((m) => m[1]));
|
|
96
140
|
const provided = new Set([...Object.keys(this.defaultArgs), ...Object.keys(args)]);
|
|
@@ -99,14 +143,46 @@ export class CommandToolExecutor {
|
|
|
99
143
|
throw new Error(`Missing required arguments: ${missing.join(", ")}`);
|
|
100
144
|
}
|
|
101
145
|
}
|
|
102
|
-
/**
|
|
103
|
-
|
|
146
|
+
/**
|
|
147
|
+
* Check validation rules against a value. Returns error message or null.
|
|
148
|
+
* When fieldName is provided, only rules targeting that field (or all fields) apply.
|
|
149
|
+
* When fieldName is omitted (rendered command check), only non-field-specific rules apply.
|
|
150
|
+
*/
|
|
151
|
+
checkRules(value, fieldName) {
|
|
104
152
|
for (const rule of this.validationRules) {
|
|
153
|
+
// Field-specific rules only match the named field.
|
|
154
|
+
// Non-field rules match everything (individual args + rendered command).
|
|
155
|
+
if (rule.field) {
|
|
156
|
+
if (fieldName !== rule.field)
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
105
159
|
if (rule.pattern && new RegExp(rule.pattern).test(value)) {
|
|
106
160
|
return rule.message ?? `Validation failed for pattern: ${rule.pattern}`;
|
|
107
161
|
}
|
|
108
162
|
}
|
|
109
163
|
return null;
|
|
110
164
|
}
|
|
165
|
+
escapeShellArg(value) {
|
|
166
|
+
return `'${value.replace(/'/g, `'"'"'`)}'`;
|
|
167
|
+
}
|
|
168
|
+
matchesDisallowed(value) {
|
|
169
|
+
for (const entry of this.disallowedCommands) {
|
|
170
|
+
const pat = entry.pattern?.trim();
|
|
171
|
+
if (!pat)
|
|
172
|
+
continue;
|
|
173
|
+
const escaped = pat.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
174
|
+
const regex = new RegExp(`(?:^|[\\s;&|()])${escaped}(?:$|[\\s;&|()])`, "i");
|
|
175
|
+
if (regex.test(value)) {
|
|
176
|
+
return entry;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
formatBlockedMessage(match) {
|
|
182
|
+
const base = `Error: Command contains blocked pattern '${match.pattern}'`;
|
|
183
|
+
return match.suggested_tool
|
|
184
|
+
? `${base}. Use the '${match.suggested_tool}' tool instead.`
|
|
185
|
+
: base;
|
|
186
|
+
}
|
|
111
187
|
}
|
|
112
188
|
//# sourceMappingURL=command.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command.js","sourceRoot":"","sources":["../../src/executors/command.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"command.js","sourceRoot":"","sources":["../../src/executors/command.ts"],"names":[],"mappings":"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"}
|
|
@@ -20,13 +20,16 @@ export interface McpProxyOptions {
|
|
|
20
20
|
authPassword?: string;
|
|
21
21
|
authToken?: string;
|
|
22
22
|
authTokenBasic?: boolean;
|
|
23
|
-
verifySsl?: boolean;
|
|
24
23
|
}
|
|
25
24
|
export declare class McpProxyExecutor implements ToolExecutor {
|
|
26
25
|
private readonly serverUrl;
|
|
27
26
|
private readonly forwardArgs;
|
|
28
27
|
private readonly timeout;
|
|
29
28
|
private readonly headers;
|
|
29
|
+
private client;
|
|
30
|
+
/** null = untried, true = SDK connected, false = fallback to raw fetch */
|
|
31
|
+
private sdkAvailable;
|
|
32
|
+
private connectPromise;
|
|
30
33
|
constructor(options: McpProxyOptions);
|
|
31
34
|
/** Fetch available tools from the remote MCP server via tools/list. */
|
|
32
35
|
fetchRemoteTools(): Promise<RemoteToolDefinition[]>;
|
|
@@ -38,10 +41,24 @@ export declare class McpProxyExecutor implements ToolExecutor {
|
|
|
38
41
|
*/
|
|
39
42
|
callTool(args: Record<string, unknown>, toolName?: string): Promise<ToolExecutionResult>;
|
|
40
43
|
validateArguments(_args: Record<string, unknown>): void;
|
|
41
|
-
/**
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
44
|
+
/**
|
|
45
|
+
* Lazily connect to the remote server via MCP SDK.
|
|
46
|
+
* On failure, sets sdkAvailable=false so callers fall back to raw fetch.
|
|
47
|
+
* Deduplicates concurrent connection attempts.
|
|
48
|
+
*/
|
|
49
|
+
private ensureConnected;
|
|
50
|
+
private doConnect;
|
|
51
|
+
/**
|
|
52
|
+
* Simplified fallback for non-MCP servers: plain JSON-RPC 2.0 POST.
|
|
53
|
+
* No session tracking, no SSE parsing, no notifications.
|
|
54
|
+
*/
|
|
55
|
+
private rawFetchRpc;
|
|
56
|
+
/** Map SDK CallToolResult to project's ToolExecutionResult. */
|
|
57
|
+
private mapSdkResult;
|
|
58
|
+
/** Extract tool definitions from a raw JSON-RPC response. */
|
|
59
|
+
private extractToolsFromRawResponse;
|
|
60
|
+
/** Parse a raw JSON-RPC response into a ToolExecutionResult. */
|
|
61
|
+
private parseRawResponse;
|
|
45
62
|
}
|
|
46
63
|
/**
|
|
47
64
|
* A thin wrapper that binds a specific remote tool name to a McpProxyExecutor.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-proxy.d.ts","sourceRoot":"","sources":["../../src/executors/mcp-proxy.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"mcp-proxy.d.ts","sourceRoot":"","sources":["../../src/executors/mcp-proxy.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,KAAK,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAErE,wDAAwD;AACxD,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACvC;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,qBAAa,gBAAiB,YAAW,YAAY;IACnD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAU;IACtC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyB;IACjD,OAAO,CAAC,MAAM,CAAuB;IACrC,0EAA0E;IAC1E,OAAO,CAAC,YAAY,CAAwB;IAC5C,OAAO,CAAC,cAAc,CAA8B;gBAExC,OAAO,EAAE,eAAe;IAyBpC,uEAAuE;IACjE,gBAAgB,IAAI,OAAO,CAAC,oBAAoB,EAAE,CAAC;IA6BzD,gDAAgD;IAC1C,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAI1E;;;OAGG;IACG,QAAQ,CACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,mBAAmB,CAAC;IAuC/B,iBAAiB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAIvD;;;;OAIG;YACW,eAAe;YAiBf,SAAS;IA6CvB;;;OAGG;YACW,WAAW;IAyCzB,+DAA+D;IAC/D,OAAO,CAAC,YAAY;IA6BpB,6DAA6D;IAC7D,OAAO,CAAC,2BAA2B;IAenC,gEAAgE;IAChE,OAAO,CAAC,gBAAgB;CA0CzB;AAED;;;;GAIG;AACH,qBAAa,uBAAwB,YAAW,YAAY;IAExD,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,cAAc;gBADd,KAAK,EAAE,gBAAgB,EACvB,cAAc,EAAE,MAAM;IAGnC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAI1E,iBAAiB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;CAGxD"}
|