Security·Runtime Defense

MCP server RASP security: runtime application self-protection and in-process argument inspection

Static analysis tells you what an MCP server might do wrong. RASP (Runtime Application Self-Protection) intercepts what it's actually doing — at the moment a tool is invoked, with the actual argument values, before the downstream call executes. For MCP servers handling LLM-generated tool calls, RASP is the last line of defense against arguments that bypass schema validation.

Why RASP is uniquely valuable for MCP servers

Traditional web application RASP instruments HTTP request handlers to detect injection in request parameters. MCP servers have a different threat model: the "attacker" is often an LLM that has been manipulated via prompt injection to generate a tool call with malicious argument values. The LLM may pass schema-valid arguments that are semantically malicious:

Schema validation (Zod, JSON Schema) catches type mismatches. RASP catches semantic attacks that pass type checks.

The MCP tool dispatch interception point

The optimal RASP hook for MCP servers is at the tool dispatch layer — between the MCP framework receiving the tool call from the LLM and the tool handler function executing. In the MCP SDK for Node.js, this is the server.tool() registration layer:

// RASP middleware for MCP tool dispatch
function raspMiddleware(toolName, schema, handler) {
  return async (args, ctx) => {
    // 1. Schema validation (type-level)
    const parsed = schema.safeParse(args);
    if (!parsed.success) throw new McpError(ErrorCode.InvalidParams, ...);

    // 2. RASP inspection (semantic-level)
    const threat = inspectArgs(toolName, parsed.data);
    if (threat) {
      audit.log({ event: "rasp_block", tool: toolName, threat, session: ctx.sessionId });
      throw new McpError(ErrorCode.InvalidParams, "Request blocked by security policy");
    }

    // 3. Execute handler with validated, inspected args
    return handler(parsed.data, ctx);
  };
}

RASP inspection rules for MCP servers

The inspectArgs function implements pattern-based checks tuned for MCP argument semantics. Key rule categories:

URL argument inspection (SSRF prevention)

Any argument containing a URL must be checked against an allowlist of permitted domains before the tool handler makes an outbound HTTP call. Reject: private IP ranges (10.x, 172.16-31.x, 192.168.x), localhost, IPv6 loopback, metadata service endpoints (169.254.169.254, fd00:ec2::254), and file:// and gopher:// schemes.

Path argument inspection (path traversal prevention)

Filename and path arguments must be checked for directory traversal sequences after URL decoding and normalization. Check for: ../, ..\, null bytes, and ensure the resolved path is within the expected base directory using path.resolve() comparison.

Shell argument inspection (command injection prevention)

If a tool argument is ever used in a shell context (even via child_process.exec() with shell interpolation), reject arguments containing: semicolons, pipes, backticks, dollar-parenthesis, newlines, and null bytes. Better: use child_process.execFile() with an args array instead of shell string interpolation, making this check unnecessary.

Prompt injection detection (agentic-specific)

Text arguments that represent user-provided content (document text, email body, ticket description) should be checked for instruction override patterns before the MCP server processes them. Heuristic patterns: ignore previous instructions, system: prefix, Assistant: prefix, STOP. New task:, and similar. Block or sanitize before the text enters any downstream LLM call.

Node.js async hooks for syscall-level RASP

For MCP servers requiring deeper runtime inspection, Node.js async_hooks can intercept asynchronous operations to track which tool invocation triggered a network call or filesystem access:

// Track async context: associate outbound calls with tool invocation
import { AsyncLocalStorage } from 'async_hooks';
const toolContext = new AsyncLocalStorage();

// In each tool handler:
toolContext.run({ tool: toolName, session: ctx.sessionId }, () => {
  return handler(args, ctx); // all async ops inside get the context
});

// In outbound HTTP interceptor:
const ctx = toolContext.getStore();
if (ctx && isBlockedDomain(url)) {
  throw new Error(`SSRF blocked: ${url} called from tool ${ctx.tool}`);
}

This pattern attributes every network call to its originating tool invocation, enabling precise audit trails and making SSRF detection context-aware — an outbound call to an internal endpoint is blocked only if it originates from a tool invocation, not from server startup code.

RASP vs WAF vs eBPF: choosing the right layer

Three complementary approaches exist for MCP server runtime defense:

Deploy all three in a high-security MCP deployment: RASP for semantic argument inspection, eBPF for syscall-level containment, and WAF for network-layer filtering. They catch different attack surfaces with minimal overlap.

Performance impact of RASP on MCP servers

Pattern matching on tool arguments adds latency at the tool dispatch layer. Benchmarks on a Node.js MCP server processing 100 concurrent tool calls:

For most MCP server deployments where the tool handler itself makes network calls (100ms+), the RASP overhead is negligible. For high-frequency lightweight tools (filesystem stat calls), profile before deploying prompt injection heuristics.

What SkillAudit checks for RASP-preventable vulnerabilities

SkillAudit's static analysis identifies the argument handling patterns that RASP is designed to catch at runtime: URL construction from args without allowlisting (SSRF), path construction from args without traversal checks, exec/spawn calls with string interpolation from args (command injection), and unvalidated JSON parse patterns. The audit report's remediation hints include both the static fix (validate at the source) and the runtime defense option (add RASP middleware) — you can implement either or both.

Find argument handling vulnerabilities before attackers do

SkillAudit scans MCP servers for SSRF, path traversal, command injection, and prompt injection patterns. Free for public repos.

Run a free audit →

Related: MCP server eBPF runtime security · MCP server input validation patterns · Anatomy of a prompt injection attack