Skip to main content
Glama
Yan-Vi
by Yan-Vi

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
EASYSPEC_PROJECTNoOptional path to project. If omitted, tools fall back to this value, and live_* tools can auto-target the single connected side panel with neither.

Instructions

Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.

This server publishes no instructions, or was last inspected before Glama recorded them.

Capabilities

Features and capabilities supported by this server

Protocol revision2025-11-25

CapabilityDetails
tools
{
  "listChanged": true
}

Tools

Functions exposed to the LLM to take actions

NameDescription
list_flowsA

List flows in a project (id, name, folder, step count).

list_scenariosA

List scenarios in a project (id, name, folder, composed flow count).

list_page_objectsC

List page objects in a project (name, folder, locator count).

get_variablesA

Get all global variables (Variables tab) for a project.

get_flowA

Get a flow's full definition, including every step.

get_scenarioA

Get a scenario's full definition (the flows it composes and their params).

get_page_objectB

Get a page object's locators and scopes. selector is a Playwright locator-chain EXPRESSION -- the text that goes after "page." (or the scope's own expression, for a scoped one), e.g. "getByRole('button', { name: 'Submit' })" or "locator('#submit')" -- never a bare selector-engine string on its own. Each shows its inferred parameters (from ${...} inside one of the expression's own string-literal arguments, see extractPoParams) alongside the raw expression. A locator with a scope field is nested under that named scope (see the scopes map) -- its own expression only needs to be unique within the scope's subtree, not the whole page.

create_flowA

Create a new, empty flow.

delete_flowB

Delete a flow (its .flow.json, .flow.ts, and flowData.ts).

set_flow_metaB

Update a flow's name, folder, description, preconditions, and/or notes.

add_stepA

Add a step to a flow, at the end by default. Use parentPath to insert into a Conditional/Repeat/Iterate step's own nested body.

add_multiple_stepsA

Add a whole ordered batch of steps to a flow in one call/one undo entry -- same placement rules as add_step (end of the array by default, parentPath for a Conditional/Repeat/Iterate body), but avoids an add_step-per-step round trip when recording several steps at once, e.g. from a live exploration session where each live_run_step action gets a matching recorded step.

update_stepB

Patch fields on an existing step. stepPath is dot-separated indices into nested .steps arrays, e.g. "2.0" is the 1st step inside the 3rd top-level step's own body.

remove_stepC

Remove a step by its path.

copy_stepsA

Copies a contiguous run of steps [from, to] (inclusive, 0-based indices within sourceParentPath's own array) from one flow into another flow -- or the same flow, for a reorder-via-copy. Deep-cloned (nested Conditional/Repeat/Iterate bodies come along intact). One undo entry, on the target flow only -- the source is never modified. Splitting a flow into two, or reusing a chunk of steps another flow already has, is one call instead of reading every step and re-adding each one by hand.

set_flow_datasetA

Add or replace a named flow-data dataset (a set of param values a flow can run with -- the Flow editor's "Flow Data" tab).

remove_flow_datasetC

Remove a named flow-data dataset.

set_state_varC

Add or replace a flow-scoped state variable (a let declared at the top of the generated function).

remove_state_varC

Remove a flow-scoped state variable.

set_output_fieldA

Add or replace one of a flow's output-data fields (what it returns to a scenario that composes it).

remove_output_fieldB

Remove one of a flow's output-data fields.

create_page_objectB

Create a new, empty page object.

delete_page_objectA

Delete a page object (fails if any flow step still binds to it via its own persistPageObject usage -- check get_flow first).

set_locatorA

Add or replace a locator on a page object. selector is a Playwright locator-chain EXPRESSION -- the text that goes after "page." (or the assigned scope's own expression, if this method has one via set_method_scope) -- e.g. "getByRole('button', { name: 'Submit' })" or "locator('#submit')", never a bare selector-engine string. A ${paramName} block (bare names only, not expressions) inside one of the expression's own string-literal arguments becomes a parametric method automatically -- see extractPoParams.

remove_locatorC

Remove a locator from a page object.

set_scopeC

Add or replace a SCOPE on a page object -- a root-element locator other locators on the same page object can be nested under (see set_method_scope), so their own selectors only need to be unique within it instead of the whole page. Useful for a reusable section (a modal, a repeated table row) -- a page object already models either a full page or a section; scopes are what make the section case actually robust. scope is stored as a bare camelCase name (auto-sanitized, e.g. "results") -- "Scope" is appended only in generated code (e.g. resultsScope), not part of the stored name. selector is a Playwright locator-chain expression, same format as set_locator's own (e.g. "locator('.results')") -- a ${paramName} block inside one of its string-literal arguments makes it parametric, for a scope reused per row/instance -- rare in practice, most scopes are static.

remove_scopeA

Remove a scope from a page object. Fails if any locator on the same page object is still assigned to it -- unassign with set_method_scope first (pass a null/omitted scope).

set_method_scopeA

Nest an existing locator under one of its OWN page object's scopes (create the scope first with set_scope) -- generated code then reads it off that scope's own element instead of the whole page. Omit/pass an empty scope to unassign, going back to page-wide.

list_utilsA

List shared utility functions in a project (name, groupName, folder, param count).

get_utilB

Get a shared utility function's full definition (groupName + params + body). A step calling it uses kind: groupName, method: name -- see add_step's own stepSchema doc.

create_utilA

Create a new, empty shared utility function (no params, empty body). Lands in the given group, defaulting to "custom-utils" if omitted -- see list_util_groups/create_util_group.

set_util_bodyA

Set a shared utility function's body -- plain TypeScript statements, no wrapping async function (...) { } (that's generated automatically from this body + the function's own params, see set_util_params). Creates the util on first use if name doesn't exist yet (landing in "custom-utils" -- move it afterward with set_util_group_name if needed). A step names this function via kind: <its groupName>, method: name (see add_step) instead of inlining code -- every step naming the same util calls this one shared function, so editing it here updates every call site at once.

set_util_paramsB

Set a shared utility function's ordered parameter names (bare identifiers, e.g. ["sql", "params"]).

delete_utilA

Delete a shared utility function. Does NOT check whether any flow step still calls it (via kind: groupName, method: name) -- check list_flows/get_flow first (same caveat as delete_page_object: this is a bare delete, no reference cascade).

list_util_groupsA

List util groups in a project (name, folder, member count). "custom-utils" always exists as the default group, even before it's ever been explicitly used.

get_util_groupA

Get a util group's metadata plus its member utils' names/params.

create_util_groupA

Create a new, empty util group. Groups are also created automatically the first time a util is placed in one (create_util's groupName, or set_util_group_name) -- this is only needed to make an empty one exist in advance.

set_util_group_nameA

Move an existing util into a (possibly brand-new) group -- e.g. moving "connectDb" out of "custom-utils" into a new "db-helpers" group. Rewrites every referencing step's own kind across every flow that calls it (a util-bound step's kind IS its group name), so this is safe to call even when flows already reference the util -- unlike delete_util/delete_page_object, this DOES cascade. Pass groupName: "custom-utils" (or omit it) to move a util back to the default group.

delete_util_groupA

Delete a util group. Does NOT destroy its member utils -- each is moved to "custom-utils" instead (their params/body are fully meaningful standalone, so this never silently discards content). Cascades every affected step's own kind the same way set_util_group_name does.

create_scenarioC

Create a new, empty scenario.

delete_scenarioC

Delete a scenario.

add_flow_to_scenarioA

Append a flow OR another already-saved scenario to a scenario's composed sequence, as a RUN CONFIG -- the exact same dataset-tokens/raw-YAML pair live_replay_flow's own dataset/params resolve, not a per-field override map. Pass exactly one of flowId (the common case) or composeScenarioId (compose another scenario instead -- both are plain functions now, so calling one from another is no different from calling a flow; rejected if it would create a composition cycle, directly or transitively). datasetTokens is a comma/space-separated list of the target's own dataset indices/names (blank = its first/default dataset); naming more than one makes this ONE entry run its target multiple times in sequence, right here in the scenario. useYaml+yaml is the raw fallback for a one-off value not worth saving as a named dataset -- a YAML/JSON object (one run), or a list of objects (one run per entry), each used as the target's own params directly (yaml is ignored unless useYaml is also true). postprocess is an expression evaluated over EACH resolved run's own params object right before it fires, receiving params (that run's own object) plus every other name already in scope (global variables, this scenario's own dataset fields, and any EARLIER entry's own captured output) -- expected to return the (possibly modified) whole params object; only meaningful for live_replay_scenario/live_start_scenario_run, evaluated in the connected tab's own page context. Output capture is automatic, not an opt-in field here, and only ever applies to a FLOW target: when it declares output fields (set_output_field) and populates its own out object via a setVariable step, that output becomes a scenario-scoped variable every LATER entry can reference by name -- <camelCase flow name>Output (a numeric suffix added only if this scenario references the same flow more than once), holding a single value normally, or an array of every run's own output if this entry resolved to more than one run. A composed-scenario entry never captures output -- scenarios don't declare an output shape.

remove_flow_from_scenarioA

Remove one of a scenario's composed flows by its index.

set_scenario_datasetB

Add or replace a named scenario-data dataset (a set of scenario-level param values, referenceable from any flow entry's own params/postprocess expressions) -- mirrors set_flow_dataset one level up.

remove_scenario_datasetC

Remove a named scenario-data dataset.

list_suitesA

List every suite entry in a project: id, folder path, which scenario it points at (plus that scenario's own name, for convenience), and its own saved run params (datasetTokens/useYaml/yaml, same shape add_flow_to_scenario stores -- absent means the scenario's own default dataset). A suite entry is a SAVED RUN, not a bare reference -- the same scenarioId can appear more than once, at different paths or even the same one, each with its own independent params.

add_to_suiteA

Place an existing scenario at a suite folder path (e.g. "regression/checkout", or "" for the root) as a SAVED RUN, not a bare reference -- datasetTokens/useYaml/yaml are the exact same run-config fields add_flow_to_scenario stores (a comma/space-separated list of this scenario's own dataset indices/names, or useYaml+yaml as a raw literal-value fallback; omit all three to use the scenario's own default dataset). Adds a NEW placement -- calling this again for the same scenarioId (same path or a different one, same params or different) places it again, it does not move or merge with an existing entry.

remove_from_suiteA

Remove one suite placement by its entry id (see list_suites). Only removes that placement -- the underlying scenario, and any of its OTHER placements, are untouched.

move_suite_entryB

Move one suite placement (by its entry id, see list_suites) to a different folder path.

set_variableC

Set a global variable (Variables tab).

unset_variableC

Remove a global variable.

live_statusA

List which projects currently have a side panel connected to this bridge (by folder name -- call this to see what's available to target, e.g. before omitting project on another live_* tool). agentName is THIS server's own stable name (e.g. "claude-1", tied to its port slot, not random) -- shown in the side panel's pending-connection list when it asks the user to approve this agent, so telling the user this name lets them confirm which pending entry to click Approve on. sessions gives each connected panel's own OPAQUE connection id (e.g. "a1b2c3d4", assigned by this bridge, meaningless on its own, and NOT the panel's own secret session name -- that value never travels from a panel to this server in any form) -- only relevant once more than one panel is connected at once; pass one as session on another live_* tool to target it specifically instead of hitting the "more than one side panel connected" ambiguity error. This never reveals a session name you weren't already told directly by the user -- the only way one reaches you at all is the user pasting it into connect_panel themselves.

connect_panelA

Establish trust with a specific side panel by its session name -- the only way to do so, since a new connection starts with no claim at all. Pass the exact session name shown in the target panel's own UI (e.g. "calm-yak-806409"); on a match the panel moves that connection from unverified to connected. Returns immediately either way -- call live_status or check the panel UI afterward to confirm it actually took.

live_replay_flowA

Replay a single flow live, in the side panel's own connected browser tab (real chrome.debugger, the user's real session/login) -- requires the side panel open and connected to this project. Targets whichever tab is pinned in the side panel's header, or the browser's actual active tab if none is pinned.

live_run_step_rangeA

Runs a contiguous [from, to] slice of an already-SAVED flow's own top-level steps live, as a real tracked Run (shows up in the Runs tab with live per-step status dots, same as live_replay_flow/live_start_run) -- for re-verifying just the steps you just added/changed instead of a full live_replay_flow from step 0 every time. Context is seeded the same way a fresh replay's first iteration would be (the chosen dataset/params -- or the flow's own first/default dataset if neither is given -- plus state-var defaults), since a mid-flow slice has no prior-steps history to inherit values from otherwise: if the steps in range reference a param/state-var, pass a dataset (or params) that actually defines it, or the slice will see it as undefined even though a full replay from step 0 would have set it correctly by this point. results has one entry per step actually attempted (stops at the first failure, same as a full replay) with its 0-based index in the flow's own step list. Blocks until the slice finishes (or fails) and moves from the Runs tab's current list to its history, same as live_replay_flow. Requires the side panel open and connected.

live_pick_elementA

Starts the element picker on the side panel's target tab (the pinned tab, or the active tab if none is pinned) and waits (up to 2 minutes) for the user to click something, returning the resulting locator expression -- the same picker the step editor's "Pick element" button uses, generated by the real Playwright engine (Locator.generateLocatorString()), ready to use as-is with set_locator/set_scope or a step's own selector. Requires the side panel open and connected. Pass pageObject+scope to restrict picking to that page object's named scope (see set_scope) -- only elements inside the scope's own root element are hoverable/clickable. The scope must be non-parametric -- a scope reused per row/instance has no single element to confine picking to here.

live_run_stepA

Runs one plain step (locator/page/assert/variable -- not a Conditional/Repeat/Iterate) live against the side panel's target tab (the pinned tab, or the active tab if none is pinned), the same way a step's own Play button would, and returns its result: capturedValue for a variable step, and generically returnValue -- whatever the underlying Playwright call itself returned (e.g. {kind:"locator", method:"count", selector:"li.item"} or {kind:"page", method:"title"}), not just the fixed capture trio. Useful for trying one action, or reading one piece of page state, without building a whole flow first. Requires the side panel open and connected.

live_run_multiple_stepsA

Runs a whole ordered sequence of plain steps (locator/page/assert/variable -- not Conditional/Repeat/Iterate) live against the side panel's target tab in one call, sharing one variable context across them (so a variable step's captured value can feed a later step's own expression arg, same as inside a real flow). Stops at the first failing step, same as a real flow would -- results has one entry per step actually attempted, so a shorter results than the input steps tells you where it stopped. Prefer this over several live_run_step calls back to back when the sequence is already decided (e.g. open a dropdown, then pick an option) -- one MCP round trip instead of one per step, and the tab stays claimed for the whole sequence instead of being released and re-claimed between each action. Requires the side panel open and connected.

live_snapshotA

Accessibility (ARIA) snapshot of the side panel's target tab (the pinned tab, or the active tab if none is pinned) -- a text tree of roles/names/values (the same format Playwright's own tooling uses), the fastest way to "see" the page well enough to find a selector for live_run_step/add_step without a screenshot. Requires the side panel open and connected.

live_screenshotA

JPEG screenshot of the side panel's target tab (the pinned tab, or the active tab if none is pinned). Prefer live_snapshot for finding a selector to act on -- reach for this when the question is genuinely visual (layout, colors, whether something rendered). Requires the side panel open and connected.

live_start_runA

Starts a flow running live on the side panel's target tab (the pinned tab, or the active tab if none is pinned) and returns immediately with a runId -- unlike live_replay_flow, this does NOT wait for the run to finish. Poll live_get_run (or live_list_runs) with the returned runId to check progress/outcome. Fails fast if that tab already has a run or single-step Play active (one at a time per tab -- see live_cancel_run to free it up). Requires the side panel open and connected.

live_list_runsA

Lists runs on the connected side panel: current (still running, one per tab) and history (finished/cancelled this session, most recent first, capped at 30). Each entry is a summary (id, name, flowId, tabId, status, step counts) -- use live_get_run for one run's full per-step detail. Safe to poll repeatedly.

live_get_runA

Full detail for one run started via live_start_run (or live_replay_flow) by its runId -- status, and every step's own status (pending/running/passed/failed/skipped) plus the error for a failed one. This is the actual "did it work, and if not where" answer after live_start_run returns. Works for both a still-running and an already-finished run.

live_cancel_runA

Cancels a still-running run by its runId (same effect as the Replay section's or Runs tab's own Cancel button) -- force-detaches that run's own target tab so an in-flight step stops immediately instead of running to its own timeout. Independent of whichever tab is currently pinned/active.

live_replay_scenarioA

Replay a whole scenario live -- runs its composed flows strictly sequentially, in the side panel's own connected browser tab (real chrome.debugger, the user's real session/login), stopping at the first flow that fails, exactly like a single flow stops at its first failing step. A flow entry whose flow declares output (see add_flow_to_scenario) automatically has its captured out bound to a name every LATER entry's own expression-mode params/postprocess can reference. Requires the side panel open and connected. Targets whichever tab is pinned in the side panel's header, or the browser's actual active tab if none is pinned.

live_start_scenario_runA

Starts a scenario running live on the side panel's target tab and returns immediately with a runId -- unlike live_replay_scenario, this does NOT wait for the run to finish. Poll live_get_scenario_run (or live_list_scenario_runs) with the returned runId to check progress/ outcome. Fails fast if that tab already has a run or single-step Play active. Requires the side panel open and connected.

live_list_scenario_runsA

Lists scenario runs on the connected side panel: current (still running, one per tab) and history (finished/cancelled this session, most recent first, capped at 30). Each entry is a summary (id, name, scenarioId, tabId, status, flows: {total, current}) -- use live_get_scenario_run for one run's full detail, including the currently-executing flow's own per-step status. Safe to poll repeatedly.

live_get_scenario_runA

Full detail for one scenario run started via live_start_scenario_run (or live_replay_scenario) by its runId -- overall status, which flow index it's on, and (via currentRun) the full per-step detail of whichever flow is currently executing, same shape live_get_run returns for a single flow. Works for both a still-running and an already-finished scenario run.

live_cancel_scenario_runA

Cancels a still-running scenario run by its runId -- stops before the next flow in the sequence starts, and force-detaches the currently-executing flow's own tab so an in-flight step stops immediately instead of running to its own timeout.

live_run_suiteA

Runs a suite (or a single suite entry) live, in parallel, across workerCount concurrently-opened dedicated tabs (a global variable, see set_variable/get_variables -- defaults to 1), trying each failing run up to attempts TOTAL times (another global variable, defaults to 1) on the same worker tab before giving up. A run that fails at least once but eventually passes is reported as "flaky", never "passed" or "failed". Pass exactly one of path (every entry placed at or under that suite folder, each expanded to its own saved run(s) -- see add_to_suite/list_suites; entries are NOT deduplicated by scenario, two placements of the same scenario with different saved params both genuinely run -- "" or omitted means the WHOLE suites tree) or scenarioIds (an explicit list bypassing suite membership entirely, each run with that scenario's own default dataset). Returns immediately with a runId; poll live_get_suite_run (or live_list_suite_runs) to check progress/outcome -- this does NOT wait for the run to finish. Each individual scenario attempt is also an ordinary scenario run, independently visible via live_list_scenario_runs/live_get_scenario_run. Requires the side panel open and connected.

live_list_suite_runsA

Lists suite runs on the connected side panel: current (still running) and history (finished/cancelled this session, most recent first, capped at 30). Each entry has the overall status and a per-scenario breakdown (status: pending/running/passed/flaky/failed, attempts count). Safe to poll repeatedly.

live_get_suite_runA

Full detail for one suite run started via live_run_suite, by its runId.

live_cancel_suite_runA

Cancels a still-running suite run by its runId -- force-interrupts whatever's actually in flight on every worker tab right now (same as live_cancel_scenario_run does for a single scenario run) and stops every worker from picking up anything further off the queue.

live_detachA

Detaches chrome.debugger from the side panel's target tab right away, instead of waiting out the ~20s idle timeout every other live_* call leaves it attached for (see live_snapshot/ live_run_step/live_pick_element -- they keep the tab attached across a quick back-and-forth burst of calls rather than detaching after each individual one, since detaching mid-exploration was closing transient page UI like an open dropdown). Call this when done with a live exploration/interaction sequence, so Chrome's "being debugged" banner does not linger on the tab longer than necessary.

live_list_tabsA

Lists every open tab in the side panel's browser window (id, title, url, which one is currently active, which one -- if any -- is pinned as the target for every other live_* call). Call this before live_switch_tab to get a valid tabId.

live_switch_tabA

Pins a specific already-open tab (by id, see live_list_tabs) as the target for every other live_* call, same as picking it from the side panel's own "Target" menu. Omit tabId to go back to following whichever tab is actually active in the browser instead of a pinned one.

live_new_tabA

Opens a new browser tab and immediately pins it as the target for every other live_* call (same as live_switch_tab right after). Optionally navigate it straight to url.

Prompts

Interactive templates invoked by user choice

NameDescription

No prompts

Resources

Contextual data attached and managed by the client

NameDescription

No resources

TDQS

B3.2/5.0

Scored across 77 tools

Disambiguation4/5

Most tools are clearly separated by entity type (flow, scenario, page object, util, suite) and action (list, get, create, delete, set, live_*). A few closely related live-execution tools could require careful reading, but descriptions generally make each one's purpose distinct.

Naming Consistency4/5

The naming largely follows a consistent snake_case verb_noun pattern such as list_flows, create_page_object, set_util_body, and live_get_run. Minor deviations like add_to_suite and connect_panel are still readable and do not seriously break the overall convention.

Tool Count1/5

With 77 tools, the surface is extremely large and far outside the typical well-scoped range. Even for a complex automation domain, this many distinct endpoints creates a heavy cognitive and discovery burden for an agent.

Completeness4/5

The toolkit covers a broad lifecycle: create/list/get/update/delete for flows, scenarios, page objects, and utils, plus live execution, run inspection, and suite management. Some possible lifecycle gaps exist, such as no explicit suite-entry removal tool, but the domain is otherwise richly covered.

Maintenance

ActivityMaintained
ResponsivenessNo issues