execute
Run sandboxed async Python code to call Amazon Ads API tools via call_tool, enabling dynamic campaign management and reporting.
Instructions
Run async Python in a sandboxed interpreter. The whole script runs as one
turn; use return to produce the tool result.
Available in scope:
await call_tool(name: str, params: dict) -> Any— calls any backend tool. Failures raiseRuntimeError(<envelope_json>)where the message body is the full v1 cross-server error envelope JSON. Inside the sandbox: try: await call_tool(name, params) except RuntimeError as e: env = json.loads(str(e)) # env['error_kind'], env['hints'], env['error_code'], # env['retryable'], env.get('_meta', {}) all available. Non-envelope failures fall back toRuntimeError("<OriginalType>: <message>"). Both forms are catchable withtry/except RuntimeError:. The format matches Amazon SP MCP for cross-server symmetry.
Sandbox guardrails (Monty interpreter):
No network:
urllib,requests,httpx,socketnot importable. Usecall_tool.No filesystem writes:
open()is missing from builtins;osandpathlibimport successfully but most side-effecting methods are gated. Tool results larger than ~1 MB may be auto-stashed by the host client.Stdlib (verified against
pydantic_monty==0.0.11; allowlist is hardcoded in Monty's compiled extension and not configurable from Python — may differ on other CodeMode hosts running a different pydantic_monty):Available:
json,re,math,datetime,sys,typing,asyncio,os,pathlib.Blocked:
collections,itertools,functools,statistics,decimal,dataclasses,random,string,time,base64,hashlib,urllib.parse. Use built-ins and comprehensions for aggregation; for hashing/encoding/URL work, request a server-side tool viaawait call_tool(...).
Builtins (verified missing / behavior differences):
hasattr(o, k)is unavailable. Use a unique sentinel withgetattr:_MISSING = [](or{}), thengetattr(o, k, _MISSING) is not _MISSING.object()is unavailable in this sandbox.callable(x)is unavailable andgetattr(x, '__call__', None) is not Noneis not reliable for built-in instances or functions in this sandbox. Prefer known-callable inputs, or guarded invocation withtry: x(...); except TypeError:when safe.No reliable capability-probing on objects. The
_MISSINGsentinel pattern above works for module attributes (e.g.getattr(math, 'pi', _MISSING)) but not for methods on built-in instances or attributes on user-defined functions. In this sandbox, built-in methods are invokable viad.keys()syntax but are not reachable as attributes viad.keys(which itself raisesAttributeError). Same for function attributes —fn.__name__raisesAttributeError.getattr(o, k, default)returnsdefaultfor these cases not becausegetattris misbehaving but because the attribute isn't there. Write code that knows the shape of its inputs rather than probing for capabilities.setattr,dir,vars,globals,locals,openare all absent.
Blocked-import error semantics: inside the sandbox,
from collections import Counterraises a stock PythonImportError(NOT aRuntimeError-wrapped envelope). Catch withexcept ImportError:(orexcept Exception:). The v1sandbox_runtime/SANDBOX_MODULE_BLOCKEDenvelope only fires when the import error is uncaught and propagates out ofexecute— at which point the calling tool layer sees the typed envelope.Unsupported-syntax error semantics:
classdefinitions,matchstatements, and other parser-not-yet-supported constructs raise aNotImplementedErrorthat DOES surface as a v1 envelope witherror_kind=sandbox_runtime/error_code=SANDBOX_RUNTIME_ERROR. Asymmetric with imports — known limitation.print()output may be discarded depending on the client path; return data via the script's final expression instead.asyncio.sleepis unavailable by design in this sandbox path. Don't sleep — chainawait call_toolcalls (e.g. poll a report-status tool) instead. For long-running reports (typically 1-20 minutes), do NOT rapid-poll inside a singleexecuteblock; return after one status check and let the user decide when to re-check.try/except/finallywork normally. To probe many candidates in one block, wrap eachawait call_tool(...)in its owntry/except RuntimeError.withworks for pure-Python context managers (e.g.decimal.localcontext()). It does NOT work foropen(...)because file I/O is blocked.json.dumps(default=...)may trip on Pydantic models; callmodel_dump()first.
Auth, region, and active profile are managed by the server. Do not pass
Amazon-Ads-AccountId, Amazon-Advertising-API-Scope, or bearer tokens in
params — set them once via set_active_identity / set_region /
set_active_profile and they ride every subsequent call_tool.
Session-scope contract:
Call
get_session_statefirst; ifstate_scope == 'request', re-runset_active_identity/set_region/set_active_profilein eachexecuteblock. Ifstate_scope == 'session', set them once via the corresponding tools and they ride subsequentcall_toolcalls in that session.To detect the transport's scope, call
get_session_stateat the start of a block. It is a read-only probe with no side effects.Rule: Re-establish context before the next tool call iff
state_scope == 'request'orstate_reasonis not null.Within a block the scope cannot change; one probe per block is sufficient.
state_reasonenumerates:"no_mcp_session"(request-scoped transport),"token_swapped"(a different bearer/refresh token arrived mid-session and the previous tenant's state was cleared —state_scopestays'session'but you must re-establish context for the new tenant), and"bridge_unavailable"(reserved; treat as'request').
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| code | Yes | Python async code to execute tool calls via call_tool(name, arguments) |