Skip to main content
The runtime execution tools let agents run code, tests, and scripts through SDL-MCP’s governance layer instead of uncontrolled shell access. Every execution is policy-evaluated, sandbox-jailed, environment-scrubbed, and audit-logged.
Runtime execution is disabled by default. You must set runtime.enabled: true in your SDL-MCP configuration before these tools become available. When disabled, all calls are rejected immediately.

sdl.runtime.execute

Runs code in a sandboxed, policy-gated subprocess scoped to a registered repository.

Supported Runtimes

The runtime parameter accepts any of the following 16 values:
ValueLanguage / EnvironmentDefault Executable
nodeNode.jsnode (or bun if available)
typescriptTypeScripttsx / ts-node
pythonPythonpython3 (Unix) / python (Windows)
shellShellbash (Unix) / cmd.exe (Windows)
goGogo run
javaJavajavac then java
kotlinKotlinkotlinc then execute
rustRustrustc then execute
cCgcc (Unix) / cl (Windows)
cppC++g++ (Unix) / cl (Windows)
csharpC#dotnet-script / csc
rubyRubyruby
phpPHPphp
perlPerlperl
rRRscript
elixirElixirelixir

Execution Modes

Code mode: Pass an inline code string via code. SDL-MCP writes it to a temp file, executes it, then cleans up. Args mode: Pass command arguments via args. The runtime’s default executable (or the executable override) is invoked directly. The two modes are mutually exclusive: use code for inline snippets, args for invoking files or commands.

Governance Model

Every call goes through the following enforcement layers:
  1. Config gateruntime.enabled must be true
  2. Policy evaluation — Runtime, executable, CWD, and timeout checked against policy
  3. Executable validation — Custom executables must be compatible with the selected runtime
  4. Environment scrubbing — Subprocesses receive only PATH and explicitly allowlisted env vars; secrets do not leak
  5. CWD jailing — Working directory is validated to stay within the repository root
  6. Concurrency limiting — Configurable maxConcurrentJobs cap prevents resource exhaustion
  7. Timeout enforcement — Hard timeout with process-tree kill
  8. Output handling — Stdout/stderr captured with configurable byte limits and persisted as gzip artifacts
  9. Audit trail — Every execution logged with policy audit hash, duration, exit code, and byte counts

Parameters

repoId
string
required
Repository identifier.
runtime
string
required
Runtime environment. One of the 16 supported values listed above.
executable
string
Override the default executable (e.g., "bun" instead of "node"). Must be compatible with the selected runtime.
args
string[]
Arguments to pass to the executable. Maximum 100. Use for invoking files or commands.
code
string
Inline code to execute (written to a temp file, then cleaned up). Maximum 1 MB. Mutually exclusive with args-only mode.
relativeCwd
string
Working directory relative to the repository root. Validated to stay within the repo. Default: "." (repo root).
timeoutMs
number
Execution timeout in milliseconds. Range: 100–300,000.
queryTerms
string[]
Keywords for excerpt matching in the output — acts as a built-in grep, extracting only matching lines from long output. Maximum 10 terms.
maxResponseLines
number
Maximum output lines returned in stdout/stderr summaries. Range: 10–1,000. Default: 100.
persistOutput
boolean
Whether to persist full output as a gzip artifact. Artifact handle returned for later retrieval via sdl.runtime.queryOutput. Default: true.
outputMode
'minimal' | 'summary' | 'intent'
Controls response verbosity and token cost:
  • "minimal" (default) — ~50 tokens. Returns status and artifact handle only. No stdout/stderr content inline. Use sdl.runtime.queryOutput to inspect the artifact.
  • "summary" — Returns head+tail of stdout and tail of stderr as stdoutSummary/stderrSummary, plus queryTerms-matched excerpts.
  • "intent" — Returns only queryTerms-matched excerpt windows. No head/tail summary.
Default is "minimal" for ~95% token savings — execute first, then query the artifact only when needed.

Response

Common fields (all outputModes):
status
string
"success", "failure", "timeout", "cancelled", or "denied".
exitCode
number | null
Process exit code.
signal
string | null
Signal that terminated the process (e.g., "SIGTERM").
durationMs
number
Execution duration in milliseconds.
artifactHandle
string | null
Handle for the persisted gzip artifact. Use with sdl.runtime.queryOutput.
policyDecision
object
{auditHash, deniedReasons}.
outputMode: "minimal" adds:
outputLines
number
Total lines captured across stdout+stderr.
outputBytes
number
Total bytes captured across stdout+stderr.
outputMode: "summary" adds:
stdoutSummary
string
Head + tail of stdout, truncated to maxResponseLines.
stderrSummary
string
Tail of stderr.
excerpts
array
Keyword-matched windows: {lineStart, lineEnd, content, source: "stdout"|"stderr"}.
truncation
object
{stdoutTruncated, stderrTruncated, totalStdoutBytes, totalStderrBytes}.
outputMode: "intent" adds:
excerpts
array
Only queryTerms-matched windows: {lineStart, lineEnd, content, source}.
truncation
object
{stdoutTruncated, stderrTruncated, totalStdoutBytes, totalStderrBytes}.
All output modes enforce a 500-character per-line cap. Lines exceeding this limit are truncated with a [truncated] suffix.

Examples

{
  "repoId": "my-repo",
  "runtime": "node",
  "args": ["--test", "tests/auth.test.ts"],
  "outputMode": "minimal",
  "timeoutMs": 30000
}

sdl.runtime.queryOutput

Retrieves and searches stored runtime output artifacts on demand. The companion tool to outputMode: "minimal" — execute first with minimal output, then query the artifact only when you need to inspect the results.
Use the "minimal" + queryOutput pattern to avoid paying for output tokens you may never need. Execute first, query only if the exit code or status suggests something worth investigating.

Artifact Persistence

When persistOutput: true (the default), sdl.runtime.execute saves the full stdout+stderr as a gzip artifact with:
  • SHA-256 content hash
  • Configurable TTL
  • Configurable size limits
  • Separate stdout and stderr streams
The artifactHandle in the execute response (e.g., "runtime-my-repo-1774356909696-fc5aa1f22e33e17c") is what you pass to queryOutput.

Parameters

artifactHandle
string
required
Handle returned by sdl.runtime.execute.
queryTerms
string[]
required
Keywords to search for in the output.
maxExcerpts
number
Maximum excerpt windows to return. Range: 1–100. Default: 10.
contextLines
number
Lines of context around each match. Range: 0–20. Default: 3.
stream
'stdout' | 'stderr' | 'both'
Which stream(s) to search. Default: "both".

Response

artifactHandle
string
Echo of the requested handle.
excerpts
array
Matched windows.
totalLines
number
Total lines in the artifact.
totalBytes
number
Total bytes in the artifact.
searchedStreams
string[]
Streams that were searched.

Example

{
  "artifactHandle": "runtime-my-repo-1774356909696-fc5aa1f22e33e17c",
  "queryTerms": ["FAIL", "Error"],
  "maxExcerpts": 5,
  "contextLines": 3
}
Execute with minimal output
{
  "repoId": "my-repo",
  "runtime": "node",
  "args": ["scripts/build.js"],
  "outputMode": "minimal",
  "timeoutMs": 120000
}
If the exit code indicates failure, query the artifact:
Query artifact for error details
{
  "artifactHandle": "<handle from execute response>",
  "queryTerms": ["error", "Error", "failed", "Cannot"],
  "contextLines": 5
}

Build docs developers (and LLMs) love