Context-aware string escaping (regex/shell/sql/json/html/url) via @mukundakatta/escape-mcp
How do I safely escape user-provided strings for embedding in different language contexts (regex patterns, shell commands, SQL queries, JSON strings, HTML content, URLs)? Need a single MCP tool that handles all common escaping contexts.
@mukundakatta/escape-mcp v0.1.0 — context-aware string escaping
Install & run: npm install @mukundakatta/escape-mcp → entry dist/server.js via stdio.
1 tool: escape ({text: string, context: "regex"|"shell"|"sql"|"json"|"html"|"url"})
Escaping behavior per context (21 calls, 100% success, p50=0ms):
regex — backslash-escapes metacharacters: .+*?()[]{}^$|\ → \\.\\+\\*\\?\\(\\)\\[\\]\\{\\}\\^\\$\\|\\\\. Empty string → empty string.
shell — wraps in single quotes, escapes embedded single quotes with '\'' (standard POSIX pattern): it's a "test" → 'it'\''s a "test"'. Command injection ($(whoami), backtick-id) safely quoted. Empty → ''.
sql — wraps in single quotes, doubles embedded quotes: O'Reilly → 'O''Reilly'. SQL injection '; DROP TABLE users; -- → safely quoted '''; DROP TABLE users; --'. Empty → ''.
json — produces valid JSON string literal with outer double quotes: "hello" → \"hello\", newline → \n, tab → \t, backslash → \\\\, control chars → \uXXXX.
html — encodes 5 dangerous chars: < → <, > → >, & → &, " → ", ' → '. Already-encoded entities get double-encoded (& → &amp;). Unicode/emoji pass through unescaped (safe in UTF-8 HTML). Named entities like ♥ get & escaped → &hearts;.
url — percent-encodes everything except unreserved chars (RFC 3986): spaces → %20, ?=& → encoded, / → %2F, UTF-8 multibyte → %XX%XX%XX, emoji → full UTF-8 percent encoding.
Key gotchas:
- Both `text` AND `context` are required — omitting either causes an error
- HTML: double-encoding trap — if input already contains
&, output will be&amp;(correct but may surprise if you escape twice) - URL: encodes path separators —
/path/to/file→%2Fpath%2Fto%2Ffile(use only for components, not full URLs) - SQL: basic quoting only — no parameterized queries or dialect awareness; use for building display strings, not as a security layer
- Shell: POSIX single-quote style — safe for bash/sh/zsh, but not Windows cmd.exe (use shellquote-mcp for multi-platform)
- Sub-millisecond after first call (6ms JIT warmup on call #1)
{ "server": "@mukundakatta/escape-mcp", "version": "0.1.0", "transport": "stdio", "entry": "dist/server.js", "tools": ["escape"], "tool_schema": { "escape": { "params": { "text": "string (required)", "context": "enum: regex|shell|sql|json|html|url (required)" }, "returns": { "result": "string (escaped)" } } }, "traces": [ { "call": 1, "context": "regex", "input": "hello.world+foo*bar?(baz)[qux]{1,3}", "output": "hello\.world\+foo\*bar\?\(baz\)\[qux\]\{1,3\}", "ms": 1 }, { "call": 3, "context": "shell", "input": "hello world; rm -rf /", "output": "'hello world; rm -rf /'", "ms": 0 }, { "call": 4, "context": "shell", "input": "it's a "test" & more | pipe", "output": "'it'\''s a "test" & more | pipe'", "ms": 0 }, { "call": 5, "context": "shell", "input": "$(whoami) `id`", "output": "'$(whoami) `id`'", "ms": 1 }, { "call": 6, "context": "sql", "input": "O'Reilly", "output": "'O''Reilly'", "ms": 0 }, { "call": 7, "context": "sql", "input": "'; DROP TABLE users; --", "output": "'''; DROP TABLE users; --'", "ms": 0 }, { "call": 9, "context": "json", "input": "He said "hello"\nand\ttabs\\backslash", "output": ""He said \"hello\"\nand\ttabs\\backslash"", "ms": 0 }, { "call": 11, "context": "html", "input": "<script>alert("XSS")</script>", "output": "<script>alert("XSS")</script>", "ms": 1 }, { "call": 14, "context": "url", "input": "hello world?key=value&foo=bar", "output": "hello%20world%3Fkey%3Dvalue%26foo%3Dbar", "ms": 0 }, { "call": 15, "context": "url", "input": "café über straße", "output": "caf%C3%A9%20%C3%BCber%20stra%C3%9Fe", "ms": 0 }, { "call": 20, "context": "html", "input": "🌍 emoji 👋🏽", "output": "🌍 emoji 👋🏽", "ms": 0 }, { "call": 21, "context": "url", "input": "🌍 emoji 👋🏽", "output": "%F0%9F%8C%8D%20emoji%20%F0%9F%91%8B%F0%9F%8F%BD", "ms": 0 } ], "stats": { "total_calls": 21, "success": 21, "failure": 0, "p50_ms": 0 } }