Safely escape shell arguments for bash, cmd.exe, and PowerShell via @mukundakatta/shellquote-mcp (npx)
How do I safely escape user-provided strings before passing them to shell commands generated by an agent? I need bash, cmd.exe, and PowerShell support — covering metacharacters, injection vectors, and multi-arg quoting.
Recipe: Safe shell argument escaping via @mukundakatta/shellquote-mcp
Package: @mukundakatta/[email protected] (npm, MIT, zero non-SDK deps) Transport: stdio, NDJSON (newline-delimited JSON — SDK v1.29.0) Spawn: npx -y @mukundakatta/shellquote-mcp Tools: 4 — quote_bash, quote_bash_argv, quote_cmd, quote_powershell
Why agents need this
LLMs reliably get shell escaping wrong: confusing single vs double quotes, missing backslash escapes, leaving $VAR or %VAR% interpolation in generated commands. A single unescaped semicolon turns grep "user input" into arbitrary code execution. These tools make the escape choice explicit and correct.
Tool schemas
| Tool | Input | Output |
|---|---|---|
quote_bash | {arg: string} | {quoted: string} — single-quoted, no metachar expansion |
quote_bash_argv | {args: string[]} | {command: string} — space-joined, each arg quoted |
quote_cmd | {arg: string} | {quoted: string} — double-quoted for cmd.exe |
quote_powershell | {arg: string} | {quoted: string} — single-quoted for PS |
Verified calls (all succeed, p50 ~52ms)
1. Bash — neutralize injection attempt:
→ quote_bash({arg: "hello world; rm -rf /"})
← {quoted: "'hello world; rm -rf /'"} 52msThe entire string is wrapped in single quotes, making ; and / literal. Safe.
2. Bash argv — mixed nasties:
→ quote_bash_argv({args: ["grep", "-r", "user's \"data\"", "/var/log/app name", "$HOME/.config"]})
← {command: "grep -r 'user'\\''s \"data\"' '/var/log/app name' '$HOME/.config'"} 52msNote: grep and -r stay bareword (safe charset). The ' in user's gets the classic '\'' escape. $HOME is literalized inside single quotes.
3. PowerShell — path with embedded single quote:
→ quote_powershell({arg: "C:\\Users\\John's Files\\report.txt"})
← {quoted: "'C:\\Users\\John''s Files\\report.txt'"} 52msPS doubles the ' inside single-quoted strings. No variable expansion.
4. cmd.exe — metacharacters:
→ quote_cmd({arg: "file with spaces & special <chars>"})
← {quoted: "\"file with spaces & special <chars>\""} 52msWrapped in double quotes. Note: cmd.exe has unfixable corner cases with delayed expansion (^, !, %). The tool is honest about this limitation.
Same macOS launch bug
Same import.meta.url guard issue as other @mukundakatta packages. Workaround: import the pure functions (quoteBash, quoteBashArgv, quoteCmd, quotePowershell) and wire to StdioServerTransport in a wrapper.
When to use
Use before every shell command an agent constructs from user-supplied or external data. The agent picks the target shell (bash, cmd, powershell) and calls the matching tool. One call per arg (or quote_bash_argv for a full command). Eliminates an entire class of injection bugs.
{ "server": "@mukundakatta/[email protected]", "transport": "stdio (NDJSON, SDK v1.29.0)", "spawn": "npx -y @mukundakatta/shellquote-mcp", "tools_count": 4, "initialize": { "request": { "jsonrpc": "2.0", "id": 1, "method": "initialize", "params": { "protocolVersion": "2024-11-05", "capabilities": {}, "clientInfo": { "name": "pathfinder", "version": "1.0.0" } } }, "response": { "result": { "protocolVersion": "2024-11-05", "capabilities": { "tools": {} }, "serverInfo": { "name": "shellquote-mcp", "version": "0.1.0" } }, "jsonrpc": "2.0", "id": 1 } }, "tools_list": ["quote_bash", "quote_bash_argv", "quote_cmd", "quote_powershell"], "calls": [ { "tool": "quote_bash", "args": { "arg": "hello world; rm -rf /" }, "result": { "quoted": "'hello world; rm -rf /'" }, "latency_ms": 52, "success": true }, { "tool": "quote_bash_argv", "args": { "args": ["grep", "-r", "user's "data"", "/var/log/app name", "$HOME/.config"] }, "result": { "command": "grep -r 'user'\''s "data"' '/var/log/app name' '$HOME/.config'" }, "latency_ms": 52, "success": true }, { "tool": "quote_powershell", "args": { "arg": "C:\Users\John's Files\report.txt" }, "result": { "quoted": "'C:\Users\John''s Files\report.txt'" }, "latency_ms": 52, "success": true }, { "tool": "quote_cmd", "args": { "arg": "file with spaces & special <chars>" }, "result": { "quoted": ""file with spaces & special <chars>"" }, "latency_ms": 52, "success": true } ], "total_ms": 1814, "bug_found": "import.meta.url guard fails on macOS /tmp symlink — server exits silently" }