Skip to content

Code mode SDK and limits

What a code mode script can call, the catalog operations and their results, call envelopes and error codes, the execute result, and every limit.

requires: codemode

A code mode script runs in the MCP gateway's sandbox each time an agent calls execute. This page lists what the script can reach, what each call returns and which limits apply. The code mode page explains when and how to use it.

The execute tool

ArgumentTypeRequiredDescription
codestringYesThe script, at most 256 KiB.
timeout_msinteger ≥ 1NoWall-clock limit for this run in milliseconds. It can only lower the listener's execution_timeout, never raise it.

Unknown arguments are rejected. execute is the only tool a code-mode gateway lists, and calling any other name returns JSON-RPC error -32002 (Tool '<name>' not found).

How a script runs

  • Async body. The code is the body of an async function, so await works at the top level and return ends the run. The returned value is serialized as JSON, and undefined becomes null.
  • Strip-only TypeScript. Type annotations, interfaces and type aliases are removed without moving any line or column. enum, namespace declarations and decorators are rejected with a ParseError.
  • Engine. The engine is QuickJS. Standard ECMAScript built-ins such as JSON, Promise, Map and Math are available. There is no fetch, no setTimeout, no module loading, no filesystem, no network and no environment.
  • Fresh state. Each run starts from a fresh copy of the engine, and nothing carries over between runs.
  • Shutdown. When the script returns, calls still in flight are cancelled. A script whose promise never settles while no calls are pending ends with an ExecutionFailure.

Globals

tools

FormBehaviour
tools["namespace.name"](args)Calls the tool with that qualified name. args defaults to {}. Returns a promise of a call envelope.
tools.namespace.name(args)The same call, written as property access.

The name is split at its first ., so a local tool name may contain dots but a namespace may not. tools cannot be enumerated or changed: Object.keys(tools) and assignments throw. To see what exists, use catalog.

catalog

Every catalog operation takes one object argument and resolves to a call envelope. Only tools the caller is authorized to use are counted, listed, searched or described.

OperationParametersdata on success
catalog.namespaces.listlimit?, offset?Page of { namespace, toolCount }, sorted by namespace.
catalog.tools.searchquery, namespace?, limit?{ items }: an array of { namespace, name, qualifiedName, description }, best match first.
catalog.tools.listnamespace, limit?, offset?Page of { namespace, name, qualifiedName, description }, sorted by name.
catalog.tools.describenamespace, name{ namespace, name, qualifiedName, description, inputSchema, outputSchema }
catalog.toolkits.listlimit?, offset?Page of { name, description, toolCount }, sorted by name.
catalog.toolkits.getname{ name, description, content }. content is text: the toolkit's instructions, then each member tool's qualified name, invocation, description and input and output schemas.
  • Search uses the gateway's tool search ranking (BM25, or remote embeddings when configured) over every permitted tool, whatever its disclosure mode. limit defaults to search.max_allowable_results (5 unless configured) and is clamped to it.
  • Pages have the shape { items, total, limit, offset, hasMore, nextOffset }. limit defaults to 20 and is capped at 100. nextOffset is present only when hasMore is true.
  • Toolkit visibility. A toolkit is listed and returned only when every tool in it exists and the caller may use all of them.

console

console.log, console.info, console.warn, console.error and console.debug each append one line to the result's logs. Arguments are joined with spaces, and anything other than a string is JSON-encoded. Each call counts toward max_host_calls. At most 128 lines are kept, and a line longer than 4096 bytes is truncated.

Call envelopes

Tool and catalog calls resolve to one of two shapes and never throw for a failed call:

{ "ok": true, "data": { "id": "c-1042" }, "meta": { "omitted": 0 } }
{ "ok": false, "error": { "code": "access_denied", "message": "Access to the requested tool was denied", "retryable": false } }

For tool calls, data is the tool's structured result when it has one: a REST tool with an output_schema, or an upstream MCP result with structuredContent. Otherwise data is the result's text content as a string (blocks joined by newlines), or null. meta.omitted counts non-text content blocks, such as images, that the envelope dropped. Catalog envelopes carry data only.

Tool call error codes

codeCause
tool_not_foundThe name is not a valid qualified name, or no such tool is registered.
access_deniedThe tool's rbac denies the caller.
invalid_inputThe arguments do not match the tool's input schema, or the call is malformed.
upstream_error, upstream_timeout, response_too_large, overflow, invalid_outputThe backend failed. The gateway's tool error is passed through, with its retryable flag and HTTP status. upstream_error also covers an unreachable upstream MCP server.
result_too_largeThis call's serialized result is larger than max_output_bytes.

Catalog error codes

coderetryableCause
invalid_inputfalseA missing or invalid parameter, such as an empty query or limit: 0.
not_foundfalseThe tool or toolkit does not exist, or the caller may not see it.
catalog_unavailabletrueThe registry could not be brought up to date, for example because a dynamic server's refresh failed.

The execute result

A run always returns a normal tools/call result whose structuredContent looks like this:

{
  "status": "completed",
  "result": { "ticket": "T-8821" },
  "error": null,
  "diagnostics": [],
  "logs": ["recent tickets: 3"],
  "toolCalls": [
    { "tool": "crm.find_customer", "ok": true, "durationMs": 38 },
    { "tool": "support.recent_tickets", "ok": true, "durationMs": 52 },
    { "tool": "billing.current_plan", "ok": true, "durationMs": 47 },
    { "tool": "support.create_ticket", "ok": true, "durationMs": 61 }
  ]
}
FieldDescription
statuscompleted or error. On error the result also sets isError: true.
resultThe script's return value, or null on error.
errorThe diagnostic on error, otherwise null. diagnostics holds the same object in a list.
logsLines from console, kept on error too.
toolCallsEvery tool call in submission order, with ok and durationMs. Catalog and log calls are not listed.

If the whole object is larger than max_output_bytes, the gateway keeps result and drops entries from the end of toolCalls, then from logs, until it fits. The result's _meta then carries "arion/codemodeTruncation": { "logsOmitted": N, "toolCallsOmitted": N }. If result alone does not fit, the run reports a ResourceLimitExceeded error instead.

Diagnostics

kindWhen
ParseErrorThe script has a syntax error or unsupported TypeScript. Carries line and column in the script as sent.
ExecutionFailureAn exception or rejection escaped the script. The message includes the stack.
TimeoutExceededexecution_timeout, or the call's timeout_ms, elapsed.
ResourceLimitExceededThe compute budget, host-call budget, result size or script size was exceeded. The message names which one.
InternalErrorSomething failed inside the gateway. It is reported generically, so no host details leak.

Errors outside the result

These come back as JSON-RPC errors, not as an execute result:

CodeMessageCause
-32600Too many Code Mode executions are activeThe listener is running max_concurrent_executions scripts. Retry later.
-32603Json schema validation error: …The execute arguments are invalid.
-32002Tool '<name>' not foundThe tool called was not execute.

Limits

LimitDefaultSet byWhen exceeded
Wall-clock time per run30 scode_mode.execution_timeout; lowered per call by timeout_msTimeoutExceeded
Compute time per run5 sFixedResourceLimitExceeded. Time spent waiting on tool and catalog calls does not count.
Sandbox memory64 MiBcode_mode.memory_limit_bytes, at most runtime.codemode.max_memory_bytesAllocation fails inside the script.
Host calls per run (tools, catalog, logs)100code_mode.max_host_callsThe call throws, and the run ends with ResourceLimitExceeded even if the script catches it.
Runs at once per listener32code_mode.max_concurrent_executions, at most runtime.codemode.pool_capacityJSON-RPC error -32600; runs are not queued.
Calls in flight within a run8code_mode.max_concurrent_tool_callsExtra calls wait their turn.
Result size1 MiBcode_mode.max_output_bytes, at least 1024A single call: result_too_large. The final result: truncation, then ResourceLimitExceeded.
Script size256 KiBFixedResourceLimitExceeded, before any sandbox starts.
Log lines128 lines of 4096 bytesFixedExtra lines are dropped and long lines truncated.
Sandboxes per process128runtime.codemode.pool_capacity or ARION_CODEMODE_POOL_CAPACITYA listener that needs more fails to load.
Memory ceiling per sandbox64 MiBruntime.codemode.max_memory_bytes or ARION_CODEMODE_MAX_MEMORY_BYTESA listener that asks for more fails to load.

Numeric code_mode fields left at 0 take their defaults.

The sandbox

  • Engine. Scripts run in a WebAssembly component on Wasmtime: QuickJS compiled for WASI and initialized ahead of time with Wizer, so each run starts from a snapshot rather than booting an interpreter.
  • Pool. Instances come from a pooling allocator sized by runtime.codemode.pool_capacity. The thread that enforces the compute budget runs only while a script is executing, so an idle gateway does no background work.
  • Isolation. The sandbox has no preopened directories, no environment variables and no sockets. Its only link to the host is an interface with three calls: request (a log line), submit (start a tool or catalog call) and next-completion (wait for one to finish). Every tool call lands on the same registry checks as a normal tools/call.
  • Custom engine. code_mode.engine_artifact_path replaces the bundled component with your own build. When the listener loads, Arion checks the component's imports against the allowed set and rejects anything else.

Continue

Start typing to search the site.

↑ ↓ to move Enter to open Esc to close