Add or update an app-level custom variable. App-level variables are shared across ALL test suites for this app (vs step-level extracts which are per-suite). Use this to declare reusable random-value generators ONCE per app, instead of redeclaring them in a prelude step of every suite. ═══════════...
Part of the Keploy server.
Free to start. No card required.
AI agents use update_app_custom_variables to create or modify resources in Keploy. Write operations carry medium risk because an autonomous agent could trigger bulk unintended modifications. Rate limits prevent a single agent session from making hundreds of changes in rapid succession. Argument validation ensures the agent passes expected values.
Without a policy, an AI agent could call update_app_custom_variables repeatedly, creating or modifying resources faster than any human could review. PolicyLayer's rate limiting ensures write operations happen at a controlled pace, and argument validation catches malformed or unexpected inputs before they reach Keploy.
Write tools can modify data. A rate limit prevents runaway bulk operations from AI agents.
{
"version": "1",
"default": "deny",
"tools": {
"update_app_custom_variables": {
"limits": [
{
"counter": "update_app_custom_variables_rate",
"window": "minute",
"max": 30,
"scope": "grant"
}
]
}
}
} See the full Keploy policy for all 103 tools.
These attack patterns abuse exactly the kind of access update_app_custom_variables gives an agent. Each links to the full case and the policy that stops it:
Other write tools across the catalogue. The same approach applies to each: rate-limit and validate the arguments.
Add or update an app-level custom variable. App-level variables are shared across ALL test suites for this app (vs step-level extracts which are per-suite). Use this to declare reusable random-value generators ONCE per app, instead of redeclaring them in a prelude step of every suite. ═══════════════════════════════════════════════════════════════════ WHEN TO USE ═══════════════════════════════════════════════════════════════════ You're drafting a POST / PUT / PATCH suite. The validator's R9 (REST) / G24 (GraphQL) rules require every mutation body to reference at least one {{var}} backed by a dynamic generator. Two ways to satisfy them: 1. App-level fn-generator (preferred) — declared ONCE here, reused by every suite. No prelude step needed. 2. Step-level extract via a prelude step (legacy) — declared per-suite. Adds a no-op step. ALWAYS prefer (1). Workflow: a) Call get_app_testing_context first — read app.appLevelCustomVariables. b) If a suitable gen* var already covers your need (e.g., genEmail for an email field) → reference {{genEmail}} in the body and skip this tool. Don't recreate. c) If no existing var fits → call this tool to create one. Future suites on this app will reuse it. ═══════════════════════════════════════════════════════════════════ NAMING CONVENTION (recommended for readability — not enforced by the validator) ═══════════════════════════════════════════════════════════════════ * Dynamic generators: by convention use gen-prefix + camelCase — genEmail, genOrderId, genTenantId, genUUID. The recommended_substitutions hints in get_app_testing_context parse these prefixes to surface "use {{genEmail}} for email fields" suggestions, so following the convention makes the agent's reuse path smoother. It is NOT enforced: the validator decides whether a {{key}} is a dynamic generator by looking at the value SHAPE alone — specifically whether the stored value parses as a JavaScript function literal. A var named "randomEmail" with a function value works fine; a var named "genEmail" with a plain string is just a static fixture. * Static fixtures: plain camelCase — seedTenantId, defaultRegion. Static vars are fine for headers / query params / assertion expected values. Static vars are REJECTED by R9/G24 if used inside POST/PUT/PATCH bodies — they'd produce identical writes across runs and break idempotency. ═══════════════════════════════════════════════════════════════════ VALUE FORMAT ═══════════════════════════════════════════════════════════════════ * type=Dynamic: a NAMED JavaScript function declaration whose body returns a value per call. The runtime registers the function in a JS VM by name and calls it on every substitution — so the form MUST be parseable as a named declaration: "function <name>(){...}" or "async function <name>(){...}". Anonymous functions ("function(){...}") and arrow functions ("() => ...", "x => x*2") are REJECTED at the MCP layer — the runtime can't execute them and would either error out or silently substitute the source text as a literal string. Example value: function genEmail(){ return 'u_' + Date.now() + '_' + Math.random().toString(36).slice(2,8) + '@example.com'; } * type=Static: a plain string. Example value: us-east-1 ═══════════════════════════════════════════════════════════════════ SEMANTICS ═══════════════════════════════════════════════════════════════════ * Upsert by key — same key called twice with different value replaces. Idempotent on retries. * Delete is NOT exposed via MCP. To remove a variable, the dev uses Settings → Global Custom Variables in the Keploy UI. * Vars created here surface in that same UI page so the dev can see and edit them. * Branching: pass branch_id to scope the var to a Keploy branch overlay. Omit to write to the app's main config. ═══════════════════════════════════════════════════════════════════ DON'T ═══════════════════════════════════════════════════════════════════ * Don't create a Dynamic var with a value that isn't a function literal — R9/G24 will reject suites using it. * Don't reuse common keys (id, email, name) without the gen prefix — collides with extract keys (R32). * Don't create overlapping vars (genEmail and genUserEmail for the same field) — clutters the app config. * Don't substitute this tool for a real prelude step when you genuinely need a value extracted from a prior response (e.g., the ID returned by a previous POST). That's still a per-suite prelude pattern.. It is categorised as a Write tool in the Keploy MCP Server, which means it can create or modify data. Consider rate limits to prevent runaway writes.
Register the Keploy MCP server in PolicyLayer and add a rule for update_app_custom_variables: allow, deny, rate-limit, or require approval. Point your MCP client at the PolicyLayer proxy URL and the rule is enforced on every call, before it reaches Keploy. Nothing to install.
update_app_custom_variables is a Write tool with medium risk. Write tools should be rate-limited to prevent accidental bulk modifications.
Yes. Add a rate_limit block to the update_app_custom_variables rule in your PolicyLayer policy. For example, setting max: 10 and window: 60 limits the tool to 10 calls per minute. Rate limits are tracked per agent session and reset automatically.
Set action: deny in the PolicyLayer policy for update_app_custom_variables. The AI agent will receive a policy violation error and cannot call the tool. You can also include a reason field to explain why the tool is blocked.
update_app_custom_variables is provided by the Keploy MCP server (https://api.keploy.io/client/v1/mcp). PolicyLayer sits as a proxy in front of this server to enforce policies before tool calls reach the server.
Deterministic rules across all 103 Keploy tools. Per-identity grants. Full audit log. Live in minutes. Nothing to install.
Free to start. No card required.
4,600+ MCP servers and 31,000+ tools scanned and risk-classified.