@ironbee-ai/devtools

MCP Server and CLI for IronBee DevTools

npm · fingerprint 8f68a1028f028f2353ae4f87 · repository · RSS

51tools
2recorded versions
1dtracked
changed today

What changed

Changed 2026-09-03 06:33 UTC

3 descriptions rewritten, 9 schema or annotation changes with the description left byte-identical, 6 tools removed.

--- pinned/a11y_take-aria-snapshot
+++ observed/a11y_take-aria-snapshot
  {
    "description": "ARIA snapshot of the page or a scoped element. Returns a tree with refs (e1, e2, ...) and a refs map.\nUse refs in interaction tools: selector \"e1\" or \"@e1\" to click/fill that element. Output includes URL, title, and YAML tree.\nRefs are valid until next snapshot or navigation. interactiveOnly: only interactive elements get refs; omit for content roles (headings, etc.) too.\ncursorInteractive: true adds refs for clickable elements without ARIA (e.g. div with cursor:pointer/onclick).\nUse with a11y_take-ax-tree-snapshot for full UI analysis.",
    "execution": {
-         "description": "Scope to this element; omit for full page. If it matches nothing, the full page is returned with a note.",
+         "description": "Scope to this element; omit for full page.",
          "type": "string"
        }
      },
--- pinned/execute
+++ observed/execute
  {
-   "description": "Batch-execute multiple tool calls in a single request via custom JavaScript. Reduces round-trips and token usage.\n\n**IMPORTANT**\n- The code is already run inside an async function. Pass only the body (statements).\n  Do NOT wrap in `async function() { ... }` or `async () => { ... }` — that causes a syntax error.\n  Write `await callTool(...); return x;` directly.\n\n**IMPORTANT:** \n- `page` (Playwright Page) is available in the VM — use it for navigation or `page.evaluate()`. \n- Prefer interaction tools with refs (e1, e2 from a11y_take-aria-snapshot); use raw Playwright only as last resort.\n- `document`/`window` are not in the VM — use `page.evaluate(() => { ... })` to run code in the browser.\n- Use `waitForNavigation: true` on interaction_click when the click navigates. \n- After navigation, do not continue with refs from the previous page — take fresh refs with a11y_take-aria-snapshot first.\n\nBindings:\n- await callTool(name, input, returnOutput?): async — always use with await. Returns the tool output for in-code use.\n  Every callTool invocation is listed in the response toolCalls array (name, in order), whether or not returnOutput is set.\n  returnOutput=true additionally attaches that call's full output to its toolCalls entry; false (default) lists the call by name only.\n  Throws on failure — execution stops at the first error; calls that ran before the failure are still listed in toolCalls (partial), with logs.\n  On failure, failedTool in the response identifies which tool caused the error.\n  Max 50 callTool invocations per execution.\n- console.log/warn/error: captured in the response logs array.\n- sleep(ms): async delay.\n- args: the parameterization object passed in the `args` input (default {}). Read values via plain JS, e.g. `const { baseUrl } = args;`.\n\nBuilt-ins: Math, JSON, Date, RegExp, Number, String, Boolean, Array, Object, Promise, Map, Set, WeakMap, WeakSet,\n           Symbol, Proxy, Reflect, URL, URLSearchParams, TextEncoder/Decoder, structuredClone,\n           crypto.randomUUID(), AbortController, setTimeout/clearTimeout.\nNOT available: require, import, process, fs, Buffer, fetch.\n\n\n**Example** — fill form, submit (with navigation wait), then snapshot and screenshot:\n  await callTool('interaction_fill', { selector: 'e3', value: 'user@test.com' });\n  await callTool('interaction_fill', { selector: 'e5', value: 'secret123' });\n  await callTool('interaction_click', { selector: 'e7', waitForNavigation: true });\n  // Or with page.locator: await page.locator('button').click();\n  // Or with page.evaluate: await page.evaluate(() => document.querySelector('button').click());\n  await callTool('a11y_take-aria-snapshot', {}, true);\n  await callTool('content_take-screenshot', {}, true);",
+   "description": "Batch-execute multiple tool calls in a single request via custom JavaScript. Reduces round-trips and token usage.\n\n**IMPORTANT** \n- The code is already run inside an async function. Pass only the body (statements). \n  Do NOT wrap in `async function() { ... }` or `async () => { ... }` — that causes a syntax error. \n  Write `await callTool(...); return x;` directly.\n\n**IMPORTANT:** \n- `page` (Playwright Page) is available in the VM — use it for navigation or `page.evaluate()`. \n- Prefer interaction tools with refs (e1, e2 from a11y_take-aria-snapshot); use raw Playwright only as last resort.\n- `document`/`window` are not in the VM — use `page.evaluate(() => { ... })` to run code in the browser.\n- Use `waitForNavigation: true` on interaction_click when the click navigates. \n- After navigation, do not continue with refs from the previous page — take fresh refs with a11y_take-aria-snapshot first.\n\nBindings:\n- await callTool(name, input, returnOutput?): async — always use with await. Returns the tool output for in-code use.\n  Every callTool invocation is listed in the response toolCalls array (name, in order), whether or not returnOutput is set.\n  returnOutput=true additionally attaches that call's full output to its toolCalls entry; false (default) lists the call by name only.\n  Throws on failure — execution stops at the first error; calls that ran before the failure are still listed in toolCalls (partial), with logs.\n  On failure, failedTool in the response identifies which tool caused the error.\n  Max 50 callTool invocations per execution.\n- console.log/warn/error: captured in the response logs array.\n- sleep(ms): async delay.\n- args: the parameterization object passed in the `args` input (default {}). Read values via plain JS, e.g. `const { baseUrl } = args;`.\n\nBuilt-ins: Math, JSON, Date, RegExp, Number, String, Boolean, Array, Object, Promise, Map, Set, WeakMap, WeakSet, \n           Symbol, Proxy, Reflect, URL, URLSearchParams, TextEncoder/Decoder, structuredClone, \n           crypto.randomUUID(), AbortController, setTimeout/clearTimeout.\nNOT available: require, import, process, fs, Buffer, fetch.\n\n\n**Example** — fill form, submit (with navigation wait), then snapshot and screenshot:\n  await callTool('interaction_fill', { selector: 'e3', value: 'user@test.com' });\n  await callTool('interaction_fill', { selector: 'e5', value: 'secret123' });\n  await callTool('interaction_click', { selector: 'e7', waitForNavigation: true });\n  // Or with page.locator: await page.locator('button').click();\n  // Or with page.evaluate: await page.evaluate(() => document.querySelector('button').click());\n  await callTool('a11y_take-aria-snapshot', {}, true);\n  await callTool('content_take-screenshot', {}, true);",
    "execution": {
      "taskSupport": "forbidden"
    },
-             },
-             "stepId": {
-               "description": "Execution id of the scenario STEP this call ran inside, when a scenario-run threaded it via _metadata.stepId. Lets a consumer correlate an internal call to its step.",
-               "type": "string"
              }
            },
            "required": [
--- pinned/interaction_click
+++ observed/interaction_click
  {
    "description": "Clicks an element. Accepts selector or ref (e.g. e1, @e1). Set waitForNavigation: true when the click opens a new page — waits for navigation then for network idle so snapshot/screenshot see full content.",
    "execution": {
-       "animate": {
-         "description": "Draw a ripple at the click point so the click is visible in recordings. Defaults to whether a screen recording is running.",
-         "type": "boolean"
-       },
        "selector": {
          "description": "CSS selector or ref from a11y snapshot (e.g. e1, @e1).",
          "type": "string"
--- pinned/interaction_drag
+++ observed/interaction_drag
  {
    "description": "Drags an element to a target location. Accepts CSS selectors or refs (e.g. e1, @e1) from the last ARIA snapshot.",
    "execution": {
-       "animate": {
-         "description": "Draw a box around the element so the action is visible in recordings. Defaults to whether a screen recording is running.",
-         "type": "boolean"
-       },
        "sourceSelector": {
          "description": "CSS selector or ref for the element to drag.",
          "type": "string"
--- pinned/interaction_fill
+++ observed/interaction_fill
  {
    "description": "Fills out an input field. Accepts a CSS selector or a ref from the last ARIA snapshot (e.g. e1, @e1).",
    "execution": {
-       "animate": {
-         "description": "Draw a box around the element so the action is visible in recordings. Defaults to whether a screen recording is running.",
-         "type": "boolean"
-       },
        "selector": {
          "description": "CSS selector or ref from a11y snapshot for the input.",
          "type": "string"
--- pinned/interaction_press-key
+++ observed/interaction_press-key
  {
    "description": "Presses a keyboard key with optional \"hold\" and auto-repeat behavior.\n\nKey facts:\n- keyboard.press(key, { delay }) does NOT trigger OS-style auto-repeat.\n- Some UI behaviors (especially scrolling) require repeated keydown events.\n- Use repeat=true + holdMs to approximate real keyboard holding.\n\nExecution logic:\n- If selector is provided, the element is focused first.\n- If holdMs is omitted or repeat=false:\n  → a single keyboard.press() is executed.\n- If holdMs is provided AND repeat=true:\n  → keyboard.press() is called repeatedly until holdMs elapses.",
    "execution": {
-       "animate": {
-         "description": "Draw a box around the element so the action is visible in recordings. Defaults to whether a screen recording is running.",
-         "type": "boolean"
-       },
        "holdMs": {
          "description": "Ms between keydown and keyup.",
          "minimum": 0,
--- pinned/interaction_select
+++ observed/interaction_select
  {
    "description": "Select an option in a dropdown. Accepts a CSS selector or a ref from the last ARIA snapshot (e.g. e1, @e1).",
    "execution": {
-       "animate": {
-         "description": "Draw a box around the element so the action is visible in recordings. Defaults to whether a screen recording is running.",
-         "type": "boolean"
-       },
        "selector": {
          "description": "CSS selector or ref from a11y snapshot for the dropdown.",
          "type": "string"
--- pinned/scenario-add
+++ observed/scenario-add
  {
    "description": "Adds a new scenario. A scenario is a reusable JS script (like execute) that can call tools via callTool().\nScenarios are stored on disk as one file per scenario (project-level by default, or global with scope=\"global\").\nOptionally declare a params contract (name + optional description/type/default/example/required): the script reads each param via the args binding, defaults are applied when a run omits the arg, and declared types are shallow-validated by <scenario-run>. Without params, args stays fully opaque.\nAn optional free-form metadata object is persisted and returned verbatim (devtools never interprets it).\nThe store also stamps createdAt / updatedAt timestamps automatically.",
    "execution": {
-       "body": {
-         "additionalProperties": false,
-         "description": "The scenario itself — the steps that run between `setup` and `teardown`. When present this is the authoritative run form and the legacy `script` field is ignored. On update, a provided body replaces the stored one wholesale; omit to keep it.",
-         "properties": {
-           "steps": {
-             "description": "Ordered steps (script/command/llm-action/include). Each llm-action needs a unique name.",
-             "items": {
-               "anyOf": [
-                 {
-                   "additionalProperties": false,
-                   "properties": {
-                     "description": {
-                       "type": "string"
-                     },
-                     "name": {
-                       "description": "REQUIRED and unique among siblings — a group exists to be named, and its name is what a reader sees in the path.",
-                       "minLength": 1,
-                       "type": "string"
-                     },
-                     "steps": {
-                       "description": "Any step kind, groups included.",
-                       "items": {
-                         "$ref": "#/properties/body/properties/steps/items"
-                       },
-                       "minItems": 1,
-                       "type": "array"
-                     },
-                     "type": {
-                       "const": "group",
-                       "type": "string"
-                     }
-                   },
-                   "required": [
-                     "type",
-                     "name",
-                     "steps"
-                   ],
-                   "type": "object"
-                 },
-                 {
-                   "anyOf": [
-                     {
-                       "additionalProperties": false,
-                       "properties": {
-                         "code": {
-                           "description": "Sandbox JS: callTool/console/sleep/args/ctx/assert available.",
-                           "type": "string"
-                         },
-                         "description": {
-                           "type": "string"
-                         },
-                         "name": {
-                           "description": "Optional stable, unique name (else the index).",
-                           "type": "string"
-                         },
-                         "type": {
-                           "const": "script",
-                           "type": "string"
-                         }
-                       },
-                       "required": [
-                         "type",
-                         "code"
-                       ],
-                       "type": "object"
-                     },
-                     {
-                       "additionalProperties": false,
-                       "properties": {
-                         "assignTo": {
-                           "description": "When set, the tool's output is stored at ctx[assignTo]. Without it the output is not kept (outputs are routinely tens of KB).",
-                           "type": "string"
-                         },
-                         "description": {
-                           "type": "string"
-                         },
-                         "input": {
-                           "additionalProperties": {},
-                           "description": "Tool input. Values may carry {{args.<path>}} / {{ctx.<path>}} references, resolved at run time: a whole-value reference preserves type, an embedded one stringifies, an unresolved one fails the step.",
-                           "type": "object"
-                         },
-                         "name": {
-                           "type": "string"
-                         },
-                         "tool": {
-                           "description": "Bare tool name, exactly what callTool takes (e.g. bdt_navigation_go-to). Never templated.",
-                           "minLength": 1,
-                           "type": "string"
-                         },
-                         "type": {
-                           "const": "tool-call",
-                           "type": "string"
-                         }
-                       },
-                       "required": [
-                         "type",
-                         "tool"
-                       ],
-                       "type": "object"
-                     },
-                     {
-                       "additionalProperties": false,
-                       "properties": {
-                         "allowNonZeroExit": {
-                           "default": false,
-                           "description": "When true a non-zero exit does not fail the step.",
-                           "type": "boolean"
-                         },
-                         "assignTo": {
-                           "description": "Store the {stdout,stderr,exitCode} result at ctx[assignTo].",
-                           "type": "string"
-                         },
-                         "command": {
-                           "description": "Host shell command (build/migrate/seed).",
-                           "type": "string"
-                         },
-                         "description": {
-                           "type": "string"
-                         },
-                         "name": {
-                           "description": "Optional stable, unique name (else the index).",
-                           "type": "string"
-                         },
-                         "type": {
-                           "const": "command",
-                           "type": "string"
-                         }
-                       },
-                       "required": [
-                         "type",
-                         "command"
-                       ],
-                       "type": "object"
-                     },
-                     {
-                       "additionalProperties": false,
-                       "properties": {
-                         "description": {
-                           "type": "string"
-                         },
-                         "intent": {
-                           "description": "Natural-language intent handed to the agent.",
-                           "type": "string"
-                         },
-                         "name": {
-                           "description": "Required stable name — its cache is keyed by it (unique within the scenario).",
-                           "type": "string"
-                         },
-                         "type": {
-                           "const": "llm-action",
-                           "type": "string"
-                         }
-                       },
-                       "required": [
-                         "type",
-                         "name",
-                         "intent"
-                       ],
-                       "type": "object"
-                     },
-                     {
-                       "additionalProperties": false,
-                       "properties": {
-                         "args": {
-                           "additionalProperties": {},
-                           "description": "Args for the ref's params — literal or `{{args.x}}` from parent args.",
-                           "type": "object"
-                         },
-                         "as": {
-                           "description": "Optional ctx namespace: the part's ctx roots at ctx[as].",
-                           "type": "string"
-                         },
-                         "description": {
-                           "type": "string"
-                         },
-                         "name": {
-                           "description": "Optional stable, unique name (else the index).",
-                           "type": "string"
-                         },
-                         "ref": {
-                           "description": "Scenario name to include (project→global).",
-                           "type": "string"
-                         },
-                         "type": {
-                           "const": "include",
-                           "type": "string"
-                         }
-                       },
-                       "required": [
-                         "type",
-                         "ref"
-                       ],
-                       "type": "object"
-                     }
-                   ]
-                 }
-               ]
-             },
-             "minItems": 1,
-             "type": "array"
-           }
-         },
-         "required": [
-           "steps"
-         ],
-         "type": "object"
-       },
        "description": {
          "description": "Description of what this scenario does.",
          "type": "string"
-       "formatVersion": {
-         "description": "Step-schema version (forward-compat guard). A value beyond what this build supports is rejected on write.",
-         "type": "integer"
-       },
        "metadata": {
          "additionalProperties": {},
-         "description": "Opaque free-form metadata, persisted and returned verbatim (devtools never interprets it). On update it is applied as a JSON Merge Patch (RFC 7386) — send ONLY the keys that change: objects merge recursively, a null value DELETES that key, an array or scalar replaces it, and any key you omit is left untouched. So you never need to read-then-resend the whole object, and you cannot accidentally drop keys another writer owns (this field is shared space).",
+         "description": "Opaque free-form metadata, persisted and returned verbatim (devtools never interprets it). On update it replaces the stored metadata wholesale when provided; omit to keep the existing value.",
          "type": "object"
        },
        "name": {
-       "requiredPlatforms": {
-         "description": "Platforms this scenario needs to run at all (browser / backend / node / python / android / terminal). Checked BEFORE any step — including setup — so a scenario that cannot work on this server says so up front instead of failing mid-run with \"tool not found\". Declare every platform any phase touches; an included scenario's requirements are unioned in automatically.",
-         "items": {
-           "minLength": 1,
-           "type": "string"
-         },
-         "type": "array"
-       },
        "scope": {
          "default": "project",
          "description": "Storage scope (default: project).",
-         "description": "Legacy single-script form. Same sandbox as <execute>: use await callTool(name, input, returnOutput?). Omit when providing `steps`.",
+         "description": "JavaScript code to execute. Same sandbox as <execute>: use await callTool(name, input, returnOutput?) to invoke tools.",
          "type": "string"
-       },
-       "setup": {
-         "additionalProperties": false,
-         "description": "Steps run BEFORE the body to establish what the scenario needs (app up, fixture seeded). Requires `steps`. Background a long-running process with its output REDIRECTED (`npm start > app.log 2>&1 &`) — an inherited stdout pipe keeps the step open until it times out.",
-         "properties": {
-           "steps": {
-             "description": "Ordered script/tool-call/command steps. llm-action and include are not allowed here.",
-             "items": {
-               "anyOf": [
-                 {
-                   "$ref": "#/properties/body/properties/steps/items/anyOf/1/anyOf/0"
-                 },
-                 {
-                   "$ref": "#/properties/body/properties/steps/items/anyOf/1/anyOf/2"
-                 }
-               ]
-             },
-             "minItems": 1,
-             "type": "array"
-           },
-           "whenReused": {
-             "description": "Whether this section runs when the scenario is REUSED (included, or invoked by a nested scenario-run). Default \"skip\" — two scenarios that both want the app up would otherwise start it twice. Ignored on the entry scenario.",
-             "enum": [
-               "skip",
-               "run"
-             ],
-             "type": "string"
-           }
-         },
-         "required": [
-           "steps"
-         ],
-         "type": "object"
-       },
-       "teardown": {
-         "$ref": "#/properties/setup",
-         "description": "Steps run AFTER the body however it ended, to undo what the run created. Does not fail fast: every step runs even if an earlier one failed, and a failure here is reported without changing the run verdict."
        }
      },
      "required": [
-       "description"
+       "description",
+       "script"
      ],
      "type": "object"
    },
-           "body": {
-             "additionalProperties": {},
-             "type": "object"
-           },
            "createdAt": {
              "type": "string"
            },
-           "formatVersion": {
-             "type": "number"
-           },
            "metadata": {
              "additionalProperties": {},
              "type": "object"
-           "requiredPlatforms": {
-             "items": {
-               "type": "string"
-             },
-             "type": "array"
-           },
            "script": {
              "type": "string"
            },
-           "setup": {
-             "additionalProperties": {},
-             "type": "object"
-           },
-           "teardown": {
-             "additionalProperties": {},
-             "type": "object"
-           },
            "updatedAt": {
              "type": "string"
            }
--- pinned/scenario-list
+++ observed/scenario-list
  {
    "description": "Lists scenarios. When scope is omitted, returns scenarios from both project and global scopes (project overrides global for same name).\nOptionally filter by metadataMatch: a subset/containment filter over the opaque metadata (a partial template the stored metadata must contain). Objects match recursively (extra sibling keys are ignored), arrays require the stored array to contain all listed elements, a scalar against a stored array uses membership, and scalars use equality. Keys are never interpreted (devtools-agnostic). Use this to find scenarios by what they cover, e.g. metadataMatch={\"ironbee\":{\"coveredPaths\":[\"src/auth/login.ts\"]}}.",
    "execution": {
-             "body": {
-               "additionalProperties": {},
-               "type": "object"
-             },
              "createdAt": {
                "type": "string"
              },
-             "formatVersion": {
-               "type": "number"
-             },
              "metadata": {
                "additionalProperties": {},
                "type": "object"
-             "requiredPlatforms": {
-               "items": {
-                 "type": "string"
-               },
-               "type": "array"
-             },
              "script": {
                "type": "string"
              },
-             "setup": {
-               "additionalProperties": {},
-               "type": "object"
-             },
-             "teardown": {
-               "additionalProperties": {},
-               "type": "object"
-             },
              "updatedAt": {
                "type": "string"
              }
--- pinned/scenario-run
+++ observed/scenario-run
  {
-   "description": "Runs a saved scenario by name (project scope first, then global).\n\nA scenario is either a single legacy JS script or an ordered list of steps\n(script / command / llm-action / include). Script steps run in the same sandbox as\nexecute (callTool/console/sleep/args), share a mutable ctx object, and can use\nan assert binding for mechanical checks. command steps run a host shell command.\ninclude steps expand another scenario inline. An llm-action step is a natural-language\nintent the agent resolves: the run PAUSES (status:'paused', with pendingStep + ctxSnapshot),\nthe agent performs the intent with its own tools, then calls scenario-run again with\nresume:true (+ resumeOutput / cache) to continue. Once resolved, the realization is\ncached in a sibling <name>.cache.json and future runs replay it without pausing (warm);\na broken cache self-heals by pausing again.\n\nPass args to parameterize the run; declared params are validated. stepByStep pauses\nafter every step; refresh ignores cache; persistCache:false skips writing the cache.\nScenarios can compose others via callTool('scenario-run', ...) (no pausing when nested;\nan unresolved llm-action there is a hard error). Max recursion depth: 5.",
+   "description": "Runs a saved scenario by name. Looks up the scenario in project scope first, then global.\nThe scenario's JS script runs in the same sandbox as execute: callTool(), console, sleep, and args are available.\nPass optional args to parameterize the run (base URL, test user, record id, …); the script reads them via the args binding (default {}), e.g. const { baseUrl } = args;.\nIf the scenario declares params, args is validated against them: declared defaults fill omitted args, required params with no value reject the run, and declared types are shallow-checked. Undeclared args (and scenarios without any params) pass through unchanged.\nFor CLI ergonomics you can also pass repeatable key=value pairs via param (the --param flag) instead of hand-writing args JSON; each value is coerced to the matching declared param's type and merged over args (param overrides args per key).\nScenarios can compose other scenarios via callTool('scenario-run', { name: '...', args: { ... } }).\nMax recursion depth: 5.",
    "execution": {
      "taskSupport": "forbidden"
    },
-         "description": "Parameterization exposed to script steps as `args`. Validated against the scenario's declared params. Latched at fresh-run start; ignored on resume.",
-         "type": "object"
-       },
-       "cache": {
-         "additionalProperties": false,
-         "description": "Freeze the just-resolved llm-action's realization script into the sibling cache file.",
-         "properties": {
-           "coveredPaths": {
-             "items": {
-               "type": "string"
-             },
-             "type": "array"
-           },
-           "resolvedAt": {
-             "type": "string"
-           },
-           "resolvedCommit": {
-             "type": "string"
-           },
-           "script": {
-             "description": "The llm-action's deterministic realization (sandbox JS).",
-             "type": "string"
-           }
-         },
-         "required": [
-           "script"
-         ],
+         "description": "Optional parameterization exposed to the scenario script as the `args` binding (default {}). Validated against the scenario's declared params when it has any (defaults applied, required enforced, declared types shallow-checked); otherwise passed through opaquely. Read via plain JS, e.g. `const { baseUrl } = args;`.",
          "type": "object"
        },
        "name": {
-         "description": "CLI ergonomics: repeatable key=value pairs (the --param flag), coerced to declared param types and merged over `args`.",
+         "description": "CLI ergonomics: repeatable key=value pairs (the --param flag). Each value is coerced to the matching declared param type and merged over `args` (param overrides args per key). Prefer `args` over MCP; use this from the CLI to avoid hand-writing --args JSON.",
          "items": {
            "type": "string"
          },
-       "persistCache": {
-         "description": "Write the authored cache to disk (default true).",
-         "type": "boolean"
-       },
-       "refresh": {
-         "anyOf": [
-           {
-             "type": "boolean"
-           },
-           {
-             "items": {
-               "type": "string"
-             },
-             "type": "array"
-           }
-         ],
-         "description": "Ignore cache: true → all llm-actions; [name,…] → matching source names."
-       },
-       "resume": {
-         "description": "Resume this scenario's paused run in this session (continues from the pending step).",
-         "type": "boolean"
-       },
-       "resumeOutput": {
-         "description": "The completed llm-action's output — merged into ctx (plain object, or a JSON-object string, → shallow merge; anything else → ctx._resume)."
-       },
-       "stepByStep": {
-         "description": "Pause after every step (default false).",
-         "type": "boolean"
-       },
        "timeoutMs": {
          "description": "Wall-clock timeout in ms (default: 30000).",
          "type": "integer"
-       "activeSteps": {
-         "description": "The absolute open-step stack after this call (outermost → innermost); [] on a terminal run.",
-         "items": {
-           "additionalProperties": false,
-           "properties": {
-             "description": {
-               "type": "string"
-             },
-             "name": {
-               "type": "string"
-             },
-             "parentStepId": {
-               "type": "string"
-             },
-             "startedAt": {
-               "type": "number"
-             },
-             "stepId": {
-               "type": "string"
-             }
-           },
-           "required": [
-             "stepId",
-             "name"
-           ],
-           "type": "object"
-         },
-         "type": "array"
-       },
-       "assertionSummary": {
-         "additionalProperties": false,
-         "properties": {
-           "failed": {
-             "type": "number"
-           },
-           "passed": {
-             "type": "number"
-           },
-           "softFailed": {
-             "type": "number"
-           }
-         },
-         "required": [
-           "passed",
-           "failed",
-           "softFailed"
-         ],
-         "type": "object"
-       },
-       "completedSteps": {
-         "items": {
-           "additionalProperties": false,
-           "properties": {
-             "assertions": {
-               "items": {
-                 "additionalProperties": true,
-                 "properties": {
-                   "kind": {
-                     "type": "string"
-                   },
-                   "message": {
-                     "type": "string"
-                   },
-                   "soft": {
-                     "type": "boolean"
-                   },
-                   "status": {
-                     "enum": [
-                       "passed",
-                       "failed"
-                     ],
-                     "type": "string"
-                   }
-                 },
-                 "required": [
-                   "kind",
-                   "status",
-                   "soft"
-                 ],
-                 "type": "object"
-               },
-               "type": "array"
-             },
-             "error": {
-               "type": "string"
-             },
-             "groupPath": {
-               "items": {
-                 "type": "string"
-               },
-               "type": "array"
-             },
-             "index": {
-               "type": "number"
-             },
-             "logs": {
-               "items": {
-                 "additionalProperties": false,
-                 "properties": {
-                   "level": {
-                     "type": "string"
-                   },
-                   "message": {
-                     "type": "string"
-                   }
-                 },
-                 "required": [
-                   "level",
-                   "message"
-                 ],
-                 "type": "object"
-               },
-               "type": "array"
-             },
-             "name": {
-               "type": "string"
-             },
-             "phase": {
-               "enum": [
-                 "setup",
-                 "body",
-                 "teardown"
-               ],
-               "type": "string"
-             },
-             "qualifiedId": {
-               "type": "string"
-             },
-             "result": {},
-             "source": {
-               "enum": [
-                 "cache",
-                 "live"
-               ],
-               "type": "string"
-             },
-             "status": {
-               "enum": [
-                 "ok",
-                 "failed",
-                 "skipped"
-               ],
-               "type": "string"
-             },
-             "toolCalls": {
-               "type": "array"
-             },
-             "type": {
-               "$ref": "#/properties/steps/items/properties/type"
-             }
-           },
-           "required": [
-             "index",
-             "type",
-             "status"
-           ],
-           "type": "object"
-         },
-         "type": "array"
-       },
-       "ctxSnapshot": {},
        "error": {
          "type": "string"
        },
-       "groups": {
-         "items": {
-           "additionalProperties": false,
-           "properties": {
-             "description": {
-               "type": "string"
-             },
-             "groupPath": {
-               "items": {
-                 "type": "string"
-               },
-               "type": "array"
-             },
-             "phase": {
-               "enum": [
-                 "setup",
-                 "body",
-                 "teardown"
-               ],
-               "type": "string"
-             }
-           },
-           "required": [
-             "phase",
-             "groupPath"
-           ],
-           "type": "object"
-         },
-         "type": "array"
-       },
        "logs": {
          "items": {
            "additionalProperties": false,
-       "pendingStep": {
-         "additionalProperties": false,
-         "properties": {
-           "ctxPath": {
-             "items": {
-               "type": "string"
-             },
-             "type": "array"
-           },
-           "healReason": {
-             "type": "string"
-           },
-           "index": {
-             "type": "number"
-           },
-           "intent": {
-             "type": "string"
-           },
-           "name": {
-             "type": "string"
-           },
-           "priorCacheScript": {
-             "type": "string"
-           },
-           "qualifiedId": {
-             "type": "string"
-           },
-           "reason": {
-             "enum": [
-               "llm-action",
-               "step-by-step"
-             ],
-             "type": "string"
-           },
-           "type": {
-             "$ref": "#/properties/steps/items/properties/type"
-           }
-         },
-         "required": [
-           "index",
-           "type",
-           "reason"
-         ],
-         "type": "object"
-       },
-       "progress": {
-         "additionalProperties": false,
-         "properties": {
-           "completedCount": {
-             "type": "number"
-           },
-           "currentIndex": {
-             "type": "number"
-           },
-           "total": {
-             "type": "number"
-           }
-         },
-         "required": [
-           "total",
-           "completedCount",
-           "currentIndex"
-         ],
-         "type": "object"
-       },
-       "recordings": {
-         "description": "Screen recordings captured for this run (file paths). Present only on the terminal response of a recorded run.",
-         "items": {
-           "type": "string"
-         },
-         "type": "array"
-       },
-       "renderHint": {
-         "type": "string"
-       },
        "result": {},
-       "runId": {
-         "description": "Per-execution run id (stable across pauses/resumes); read by ironbee-cli to correlate and finalize the run. Top-level step runs only.",
-         "type": "string"
-       },
        "scenarioName": {
          "type": "string"
        },
-       "status": {
-         "enum": [
-           "completed",
-           "paused",
-           "failed"
-         ],
-         "type": "string"
-       },
-       "stepEvents": {
-         "description": "Per-call step-timeline delta (step_start/step_end transitions since the last response), replayed by ironbee-cli. Each lifecycle phase's steps hang under a synthetic phase ROOT span named <setup> / <main> / <teardown> — the only parentless steps of a run. Top-level step runs only.",
-         "items": {
-           "additionalProperties": false,
-           "properties": {
-             "description": {
-               "type": "string"
-             },
-             "duration": {
-               "type": "number"
-             },
-             "endedAt": {
-               "type": "number"
-             },
-             "error": {
-               "type": "string"
-             },
-             "event": {
-               "enum": [
-                 "start",
-                 "end"
-               ],
-               "type": "string"
-             },
-             "name": {
-               "type": "string"
-             },
-             "parentStepId": {
-               "type": "string"
-             },
-             "startedAt": {
-               "type": "number"
-             },
-             "status": {
-               "enum": [
-                 "failed",
-                 "passed",
-                 "skipped"
-               ],
-               "type": "string"
-             },
-             "stepId": {
-               "type": "string"
-             }
-           },
-           "required": [
-             "event",
-             "stepId",
-             "name"
-           ],
-           "type": "object"
-         },
-         "type": "array"
-       },
-       "steps": {
-         "items": {
-           "additionalProperties": false,
-           "properties": {
-             "groupPath": {
-               "items": {
-                 "type": "string"
-               },
-               "type": "array"
-             },
-             "index": {
-               "type": "number"
-             },
-             "name": {
-               "type": "string"
-             },
-             "phase": {
-               "enum": [
-                 "setup",
-                 "body",
-                 "teardown"
-               ],
-               "type": "string"
-             },
-             "qualifiedId": {
-               "type": "string"
-             },
-             "status": {
-               "enum": [
-                 "ok",
-                 "failed",
-                 "skipped",
-                 "pending",
-                 "not-started"
-               ],
-               "type": "string"
-             },
-             "type": {
-               "enum": [
-                 "script",
-                 "tool-call",
-                 "command",
-                 "llm-action"
-               ],
-               "type": "string"
-             }
-           },
-           "required": [
-             "index",
-             "type",
-             "phase",
-             "status"
-           ],
-           "type": "object"
-         },
-         "type": "array"
-       },
-       "teardownErrors": {
-         "description": "Why teardown steps failed, if any did. Separate from `error` on purpose: a failed cleanup does not mean the scenario failed.",
-         "items": {
-           "type": "string"
-         },
-         "type": "array"
-       },
        "toolCalls": {
-         "description": "Nested calls made by script/warm-cache steps in THIS response (ordered).",
+         "description": "Complete, ordered list of every nested call the scenario made (from the delegated execute). Each entry always has `name`; `output` only when returnOutput=true; composite calls expose the inner run as `children`.",
          "items": {
            "additionalProperties": false,
            "properties": {
-             },
-             "stepId": {
-               "description": "Execution id of the scenario STEP this call ran inside, when a scenario-run threaded it via _metadata.stepId. Lets a consumer correlate an internal call to its step.",
-               "type": "string"
              }
            },
            "required": [
-       },
-       "verdict": {
-         "enum": [
-           "pass",
-           "fail",
-           "soft-fail"
-         ],
-         "type": "string"
        }
      },
      "required": [
--- pinned/scenario-search
+++ observed/scenario-search
  {
    "description": "Full-text search over scenario name + description across both project and global scopes.\nUses configurable search strategy (SEARCH_STRATEGY or SCENARIO_SEARCH_STRATEGY env var).\nReturns matching scenarios (including their metadata) ranked by relevance.\nOptionally narrow the corpus with metadataMatch (subset/containment over the opaque metadata) before ranking — e.g. text-search only among scenarios that cover a given path. For a pure metadata lookup with no text query, use scenario-list with metadataMatch.",
    "execution": {
-             "body": {
-               "additionalProperties": {},
-               "type": "object"
-             },
              "createdAt": {
                "type": "string"
              },
-             "formatVersion": {
-               "type": "number"
-             },
              "metadata": {
                "additionalProperties": {},
                "type": "object"
-             "requiredPlatforms": {
-               "items": {
-                 "type": "string"
-               },
-               "type": "array"
-             },
              "score": {
                "type": "number"
              },
-             "setup": {
-               "additionalProperties": {},
-               "type": "object"
-             },
-             "teardown": {
-               "additionalProperties": {},
-               "type": "object"
-             },
              "updatedAt": {
                "type": "string"
              }
--- pinned/scenario-update
+++ observed/scenario-update
  {
-   "description": "Updates an existing scenario's description, script, params, and/or metadata.\nWrite semantics differ between the two, deliberately. params is a wholesale replace: a provided array replaces the stored one (that is how you reorder or drop an entry); omit it to keep the current contract. metadata is a JSON Merge Patch (RFC 7386): send only the keys that change — objects merge recursively, a null value deletes that key, an array/scalar replaces it, omitted keys survive. Metadata is shared space (IronBee's ironbee.* keys alongside the user's own), so patching is what keeps one writer from silently dropping another's. The store refreshes updatedAt automatically.",
+   "description": "Updates an existing scenario's description, script, params, and/or metadata.\nParams and metadata write semantics are shallow replace: when an array/object is provided it replaces the stored one wholesale; omit it to keep the current value. The store refreshes updatedAt automatically.",
    "execution": {
      "taskSupport": "forbidden"
    },
-       "body": {
-         "additionalProperties": false,
-         "description": "The scenario itself — the steps that run between `setup` and `teardown`. When present this is the authoritative run form and the legacy `script` field is ignored. On update, a provided body replaces the stored one wholesale; omit to keep it.",
-         "properties": {
-           "steps": {
-             "description": "Ordered steps (script/command/llm-action/include). Each llm-action needs a unique name.",
-             "items": {
-               "anyOf": [
-                 {
-                   "additionalProperties": false,
-                   "properties": {
-                     "description": {
-                       "type": "string"
-                     },
-                     "name": {
-                       "description": "REQUIRED and unique among siblings — a group exists to be named, and its name is what a reader sees in the path.",
-                       "minLength": 1,
-                       "type": "string"
-                     },
-                     "steps": {
-                       "description": "Any step kind, groups included.",
-                       "items": {
-                         "$ref": "#/properties/body/properties/steps/items"
-                       },
-                       "minItems": 1,
-                       "type": "array"
-                     },
-                     "type": {
-                       "const": "group",
-                       "type": "string"
-                     }
-                   },
-                   "required": [
-                     "type",
-                     "name",
-                     "steps"
-                   ],
-                   "type": "object"
-                 },
-                 {
-                   "anyOf": [
-                     {
-                       "additionalProperties": false,
-                       "properties": {
-                         "code": {
-                           "description": "Sandbox JS: callTool/console/sleep/args/ctx/assert available.",
-                           "type": "string"
-                         },
-                         "description": {
-                           "type": "string"
-                         },
-                         "name": {
-                           "description": "Optional stable, unique name (else the index).",
-                           "type": "string"
-                         },
-                         "type": {
-                           "const": "script",
-                           "type": "string"
-                         }
-                       },
-                       "required": [
-                         "type",
-                         "code"
-                       ],
-                       "type": "object"
-                     },
-                     {
-                       "additionalProperties": false,
-                       "properties": {
-                         "assignTo": {
-                           "description": "When set, the tool's output is stored at ctx[assignTo]. Without it the output is not kept (outputs are routinely tens of KB).",
-                           "type": "string"
-                         },
-                         "description": {
-                           "type": "string"
-                         },
-                         "input": {
-                           "additionalProperties": {},
-                           "description": "Tool input. Values may carry {{args.<path>}} / {{ctx.<path>}} references, resolved at run time: a whole-value reference preserves type, an embedded one stringifies, an unresolved one fails the step.",
-                           "type": "object"
-                         },
-                         "name": {
-                           "type": "string"
-                         },
-                         "tool": {
-                           "description": "Bare tool name, exactly what callTool takes (e.g. bdt_navigation_go-to). Never templated.",
-                           "minLength": 1,
-                           "type": "string"
-                         },
-                         "type": {
-                           "const": "tool-call",
-                           "type": "string"
-                         }
-                       },
-                       "required": [
-                         "type",
-                         "tool"
-                       ],
-                       "type": "object"
-                     },
-                     {
-                       "additionalProperties": false,
-                       "properties": {
-                         "allowNonZeroExit": {
-                           "default": false,
-                           "description": "When true a non-zero exit does not fail the step.",
-                           "type": "boolean"
-                         },
-                         "assignTo": {
-                           "description": "Store the {stdout,stderr,exitCode} result at ctx[assignTo].",
-                           "type": "string"
-                         },
-                         "command": {
-                           "description": "Host shell command (build/migrate/seed).",
-                           "type": "string"
-                         },
-                         "description": {
-                           "type": "string"
-                         },
-                         "name": {
-                           "description": "Optional stable, unique name (else the index).",
-                           "type": "string"
-                         },
-                         "type": {
-                           "const": "command",
-                           "type": "string"
-                         }
-                       },
-                       "required": [
-                         "type",
-                         "command"
-                       ],
-                       "type": "object"
-                     },
-                     {
-                       "additionalProperties": false,
-                       "properties": {
-                         "description": {
-                           "type": "string"
-                         },
-                         "intent": {
-                           "description": "Natural-language intent handed to the agent.",
-                           "type": "string"
-                         },
-                         "name": {
-                           "description": "Required stable name — its cache is keyed by it (unique within the scenario).",
-                           "type": "string"
-                         },
-                         "type": {
-                           "const": "llm-action",
-                           "type": "string"
-                         }
-                       },
-                       "required": [
-                         "type",
-                         "name",
-                         "intent"
-                       ],
-                       "type": "object"
-                     },
-                     {
-                       "additionalProperties": false,
-                       "properties": {
-                         "args": {
-                           "additionalProperties": {},
-                           "description": "Args for the ref's params — literal or `{{args.x}}` from parent args.",
-                           "type": "object"
-                         },
-                         "as": {
-                           "description": "Optional ctx namespace: the part's ctx roots at ctx[as].",
-                           "type": "string"
-                         },
-                         "description": {
-                           "type": "string"
-                         },
-                         "name": {
-                           "description": "Optional stable, unique name (else the index).",
-                           "type": "string"
-                         },
-                         "ref": {
-                           "description": "Scenario name to include (project→global).",
-                           "type": "string"
-                         },
-                         "type": {
-                           "const": "include",
-                           "type": "string"
-                         }
-                       },
-                       "required": [
-                         "type",
-                         "ref"
-                       ],
-                       "type": "object"
-                     }
-                   ]
-                 }
-               ]
-             },
-             "minItems": 1,
-             "type": "array"
-           }
-         },
-         "required": [
-           "steps"
-         ],
-         "type": "object"
-       },
        "description": {
          "description": "New description (omit to keep current).",
          "type": "string"
-       "formatVersion": {
-         "description": "Step-schema version (forward-compat guard). A value beyond what this build supports is rejected on write.",
-         "type": "integer"
-       },
        "metadata": {
          "additionalProperties": {},
-         "description": "Opaque free-form metadata, persisted and returned verbatim (devtools never interprets it). On update it is applied as a JSON Merge Patch (RFC 7386) — send ONLY the keys that change: objects merge recursively, a null value DELETES that key, an array or scalar replaces it, and any key you omit is left untouched. So you never need to read-then-resend the whole object, and you cannot accidentally drop keys another writer owns (this field is shared space).",
+         "description": "Opaque free-form metadata, persisted and returned verbatim (devtools never interprets it). On update it replaces the stored metadata wholesale when provided; omit to keep the existing value.",
          "type": "object"
        },
        "name": {
-       "requiredPlatforms": {
-         "description": "Platforms this scenario needs to run at all (browser / backend / node / python / android / terminal). Checked BEFORE any step — including setup — so a scenario that cannot work on this server says so up front instead of failing mid-run with \"tool not found\". Declare every platform any phase touches; an included scenario's requirements are unioned in automatically.",
-         "items": {
-           "minLength": 1,
-           "type": "string"
-         },
-         "type": "array"
-       },
        "scope": {
          "default": "project",
          "description": "Storage scope (default: project).",
-       },
-       "setup": {
-         "additionalProperties": false,
-         "description": "Steps run BEFORE the body to establish what the scenario needs (app up, fixture seeded). Requires `steps`. Background a long-running process with its output REDIRECTED (`npm start > app.log 2>&1 &`) — an inherited stdout pipe keeps the step open until it times out.",
-         "properties": {
-           "steps": {
-             "description": "Ordered script/tool-call/command steps. llm-action and include are not allowed here.",
-             "items": {
-               "anyOf": [
-                 {
-                   "$ref": "#/properties/body/properties/steps/items/anyOf/1/anyOf/0"
-                 },
-                 {
-                   "$ref": "#/properties/body/properties/steps/items/anyOf/1/anyOf/2"
-                 }
-               ]
-             },
-             "minItems": 1,
-             "type": "array"
-           },
-           "whenReused": {
-             "description": "Whether this section runs when the scenario is REUSED (included, or invoked by a nested scenario-run). Default \"skip\" — two scenarios that both want the app up would otherwise start it twice. Ignored on the entry scenario.",
-             "enum": [
-               "skip",
-               "run"
-             ],
-             "type": "string"
-           }
-         },
-         "required": [
-           "steps"
-         ],
-         "type": "object"
-       },
-       "teardown": {
-         "$ref": "#/properties/setup",
-         "description": "Steps run AFTER the body however it ended, to undo what the run created. Does not fail fast: every step runs even if an earlier one failed, and a failure here is reported without changing the run verdict."
        }
      },
      "required": [
-           "body": {
-             "additionalProperties": {},
-             "type": "object"
-           },
            "createdAt": {
              "type": "string"
            },
-           "formatVersion": {
-             "type": "number"
-           },
            "metadata": {
              "additionalProperties": {},
              "type": "object"
-           "requiredPlatforms": {
-             "items": {
-               "type": "string"
-             },
-             "type": "array"
-           },
            "script": {
              "type": "string"
            },
-           "setup": {
-             "additionalProperties": {},
-             "type": "object"
-           },
-           "teardown": {
-             "additionalProperties": {},
-             "type": "object"
-           },
            "updatedAt": {
              "type": "string"
            }

tool removed: flush

tool removed: o11y_get-session-logs

tool removed: o11y_get-session-traces

tool removed: o11y_get-trace

tool removed: o11y_get-trace-logs

tool removed: scenario-recorded-actions

Current tools

Show all 51 tool fingerprints
a11y_take-aria-snapshot
8d694ed08c61cd2e
a11y_take-ax-tree-snapshot
0119448ebf5cbb56
content_get-as-html
a6c9154eabbfd2c1
content_get-as-text
46c7007b391ed4b6
content_save-as-pdf
f1b6b82972ef8c4e
content_start-recording
b94430a4fd33061f
content_stop-recording
77c144fb94d7364a
content_take-screenshot
158c39102bbfea74
debug_add-watch
af7bcdf5aa64b3d6
debug_clear-probe-snapshots
851785f90926409b
debug_clear-probes
1dee8a5671a87f7c
debug_get-probe-snapshots
713bd6f027c4eb07
debug_list-probes
e3091f4e83b7a85c
debug_put-exceptionpoint
2a430fce1fbcd4df
debug_put-logpoint
546c0bebad10ed9f
debug_put-tracepoint
22ca755ca4641460
debug_remove-probe
c887a715f03878c5
debug_resolve-source-location
912ab037cc36f1ec
debug_status
57cbf99dced9ec21
execute
8f24bfdd70187029
interaction_click
6f63aee6779e431e
interaction_drag
802096a83ba681ae
interaction_fill
d1589f4ac50103ca
interaction_hover
17205ce9076d1337
interaction_press-key
ec2776183e7ac828
interaction_resize-viewport
6d0fa8aff49c769d
interaction_resize-window
2c489676f647a1e1
interaction_scroll
68e8ec4f58a0e0a8
interaction_select
1eacb00de650d468
navigation_go-back-or-forward
7c5ba71fa8a5febf
navigation_go-to
7f20a2ee554fa7b3
navigation_reload
44acbbadbe784c62
o11y_get-console-messages
8c51a51a673cb2e1
o11y_get-http-requests
ecf78c993d6ff609
o11y_get-trace-context
a397fbdf5402a67f
o11y_get-web-vitals
7a3ab268b542f0fe
o11y_new-trace-id
64d22c56a7836171
o11y_set-trace-context
3e9ce55de363b2f6
react_get-component-for-element
85bc613a2e0e786e
react_get-element-for-component
3a7b78a1bbe4c3c0
scenario-add
1ae5d8fd4f2af0c0
scenario-delete
e9c2a8662e4a1269
scenario-list
0fe542dd9aa5f5a3
scenario-run
d0ae673c1efd0319
scenario-search
b1f963f0e444c53c
scenario-update
cceabbdf55f78aea
stub_clear
af1065677435b5dc
stub_intercept-http-request
9f23a6762d5d6b49
stub_list
d45181dff2174247
stub_mock-http-response
657bab15955e5f18
sync_wait-for-network-idle
63df354ca4744547

Watch this server yourself

If you run this server, put the proxy in front of it. It pins these exact fingerprints on first connect and stops the session if they move.

npx --yes mcp-pin@0.1.0 -- <your @ironbee-ai/devtools command>

Or subscribe to this page's RSS feed to be told when it changes.

Badge

mcp-pin status badge for @ironbee-ai/devtools

The badge states one fact about time and nothing else. It never claims a server is safe.

[![mcp-pin](https://mcp-pin.gautamkhosla.com/badge/9bebbec14fb8af60.svg)](https://mcp-pin.gautamkhosla.com/servers/9bebbec14fb8af60.html)