Skip to main content
Glama

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
WEBSPEED_API_KEYYesYour Web Speed API key
WEBSPEED_SERVER_URLNoOverride API server URL (must be https://)

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": false
}
prompts
{
  "listChanged": false
}
resources
{
  "subscribe": false,
  "listChanged": false
}
experimental
{}

Tools

Functions exposed to the LLM to take actions

NameDescription
store_credentialA

Save login credentials to the system keychain (macOS/Windows/Linux).

Credentials are stored locally and NEVER sent to any server. Use site as a short identifier, e.g. "indiehackers", "twitter", "gmail".

setup_browserA

Set up Chrome or Edge for agent use (macOS and Windows).

Run this ONCE (with your browser closed). It:

  1. Creates a dedicated agent profile at ~/.webspeed/chrome-debug/ (macOS) or %LOCALAPPDATA%\WebSpeedAgent\chrome-debug\ (Windows) — a non-default user data directory, which is required by Chrome before it will open the remote debugging port.

  2. Copies your existing Chrome cookies into that profile so you are already logged into all your sites when the agent opens the browser.

  3. macOS: installs ~/bin/chrome-agent and adds a shell alias in ~/.zshrc. Windows: writes chrome-agent.bat to your Desktop.

After setup:

  • macOS: type 'chrome-agent' in Terminal to open Chrome

  • Windows: double-click chrome-agent.bat on your Desktop

  • Tell the agent: open_browser(browser="chrome", cdp_url="http://localhost:9222")

  • The agent opens a new tab in your real Chrome with all your logins active

Re-run setup_browser() any time you want to sync fresh cookies from your main Chrome profile into the agent profile (close Chrome first).

Args: browser: "chrome" (default) or "edge".

open_browserA

Open a browser for automation.

browser — which browser to use: "chrome" (default), "firefox", or "edge".

── Chrome default behaviour ────────────────────────────────────────────────── For Chrome, CDP is tried automatically first. If the user has run 'chrome-agent' (which opens Chrome with --remote-debugging-port=9222), the agent connects to that existing window and opens a new tab — the user's real Chrome with all their logins, cookies, and extensions.

If Chrome is not running with the debug port, a helpful message is returned explaining how to start it.

── Firefox ─────────────────────────────────────────────────────────────────── Imports cookies from the user's Firefox profile (read-only) into a fresh Playwright session. Pass profile_path="auto" to detect the profile.

── Manual overrides ────────────────────────────────────────────────────────── cdp_url: connect to a specific debug URL (e.g. non-default port). profile_path: use an explicit profile directory (Chrome/Firefox/Edge). session_name: persist cookies across fresh Playwright sessions.

Args: browser: "chrome" (default), "firefox", or "edge". session_name: Cookie-persist name for standard/fresh mode. headless: Hide the window in standard/profile mode (default False). cdp_url: Override the CDP URL (default for Chrome: http://localhost:9222). profile_path: Launch with an existing browser profile ("auto" or full path).

navigateA

Navigate to a URL and return the page title and final URL.

Always call this before interacting with a new page.

Args: url: The URL to navigate to. expect_url_contains: Optional substring the final URL should contain. If the page redirected elsewhere (common on SPAs), a 'spa_redirect' warning is included in the result so the agent knows to adjust its approach.

loginA

Fill a login form and submit it.

Credentials: provide either site (to load from keychain) OR username + password directly.

Selectors: if omitted, common patterns are tried automatically (input[type=email], input[name=username], etc.).

Use navigate() to go to the login page first.

read_pageA

Extract structured data from the current page via the Web Speed API.

Returns type-aware structured JSON: article → title, author, sections, links product → name, price, availability, specs listing → items with title, url, price, snippet other → headings, navigation, forms, text_blocks

Costs 1 Web Speed credit. Requires WEBSPEED_API_KEY.

clickA

Click an element by CSS selector.

The wait arguments all run inside THIS call. Reach for them instead of following a click with a separate wait tool — the extra round-trip costs far more than the wait. Prefer wait_for / wait_for_predicate / wait_until over wait_ms: a fixed sleep is either too short (flaky) or too long (slow), while a condition returns the moment it is satisfied.

Args: selector: CSS selector for the element to click. wait_for_navigation: Wait for a page load after clicking (default True). Set to False for clicks that trigger in-page UI changes like modals, dropdowns, or expanding sections. wait_for: CSS selector to wait for AFTER clicking — use this when the click opens a modal or triggers async UI rendering. The tool waits up to 5 s for the element to appear before returning. wait_ms: Fixed sleep after the click. Discouraged — use wait_until or wait_for_predicate, which finish as soon as the page is ready. wait_for_predicate: JS expression polled (up to 5 s) until it returns truthy, e.g. "!document.querySelector('.spinner')". wait_until: Readiness signal — 'dom_settled' (wait for the DOM to stop changing; the right replacement for wait_ms), 'networkidle', 'load', 'domcontentloaded', 'settle', or 'none'. Defaults to the historical behaviour: settle unless wait_for was given.

Waits that time out do not fail the click — the click already happened. They come back in a warnings list so you can see, for instance, that the modal you expected never opened.

fill_fieldA

Type a value into a form field.

Standard mode (use_keyboard=False, default): sets the field value directly. Works for plain <input> and <textarea> elements.

Keyboard mode (use_keyboard=True): simulates real keystrokes (keydown → keypress → input → keyup per character). Use this for:

  • contenteditable divs (X/Twitter post box, Notion, Slack, etc.)

  • React / Vue inputs that ignore programmatic .value changes

  • Sites that check for "trusted" input events to prevent botting

For X (Twitter): click the "What's happening?" box first, then call fill_field with use_keyboard=True. This fires the React-compatible events that enable the Post button.

Args: selector: CSS selector for the input or contenteditable element. value: Text to type. Never include \n — it will be stripped. A trailing \n is treated as Tab (advance to next field). press_tab: Press Tab after filling to move focus to the next field. use_keyboard: Simulate real keystrokes instead of direct fill. delay_ms: Milliseconds between keystrokes in keyboard mode. 0 = fast (default). Use 30–80 for sites that check typing cadence.

hoverA

Move the pointer over an element, without clicking.

Whole menus exist only on hover — nav dropdowns, tooltips, the row of icons that appears on a table row. A synthetic mouseover event dispatched from JavaScript often will not open them, because the site listens for a trusted pointer or checks :hover in CSS. This moves the real pointer.

Args: selector: CSS selector for the element to hover. wait_for: CSS selector to wait for afterwards (the menu that should open). wait_for_predicate: JS expression polled until truthy afterwards. wait_until: Readiness signal afterwards — 'none' (default), 'dom_settled', 'networkidle', 'load', 'domcontentloaded', 'settle'.

scrollA

Scroll the page, or bring an element into view.

Needed for more than reading: infinite feeds only load the next batch once you reach the bottom, and lazy images never request until they approach the viewport. An element below the fold can also be genuinely unclickable.

Args: to: 'down', 'up', 'top', 'bottom', or 'element' (with selector). selector: Element to scroll into view. Implies to='element'. amount_px: Pixels to scroll for 'down'/'up' (default 600). wait_until: Readiness signal afterwards. Defaults to 'dom_settled', which is what makes this useful on infinite scroll — it returns once the newly loaded rows stop arriving.

select_optionA

Choose an option in a dropdown.

fill_field cannot do this — typing into a does nothing. Pick ONE of value / label / index:

value  matches the option's `value` attribute (most reliable)
label  matches the visible text
index  zero-based position

Args: selector: CSS selector for the element. value: The option's value attribute. label: The option's visible text. index: Zero-based option position.

go_backA

Go back in browser history.

The honest way out of a wrong turn. Re-navigating to a remembered URL is not the same thing: it drops scroll position, in-page state and any POST result, and on a SPA the URL you remember may not rebuild the view you were on.

Args: steps: How many entries to go back (1–20). wait_until: Readiness signal after the last step. Defaults to 'settle'.

press_keysA

Send real keystrokes to the page, rather than into a form field.

fill_field writes into an <input>. This types at whatever holds keyboard focus, which is what word games, canvas editors (Figma, Excalidraw), terminal emulators, and keyboard-shortcut UIs actually listen to: they bind keydown/keyup on window or document, so setting an input's value never reaches them and there is often no input to target in the first place.

Examples: press_keys(text="crane", keys=["Enter"]) # type a word, submit it press_keys(keys=["ArrowDown"], repeat=3) # move a selection press_keys(keys=["Control+a", "Backspace"]) # select all, clear press_keys(text="hello", selector="#chat") # focus first, then type

Args: text: Literal text to type one character at a time, firing the full keydown → keypress → input → keyup sequence per character. Typed BEFORE keys, so text="crane", keys=["Enter"] does the right thing. keys: Key names pressed in order — ["Enter"], ["Escape"], ["ArrowLeft"] — or chords like ["Control+a"], ["Shift+Tab"]. Playwright names: Enter, Tab, Escape, Backspace, Delete, ArrowUp/Down/Left/Right, Home, End, PageUp, PageDown, F1–F12, and single characters. selector: CSS selector to focus first. Omit to send keys to whatever already has focus — the usual case for games and canvas apps. delay_ms: Milliseconds per keystroke (0–1000). 0 is fastest; use 20–80 on sites that check typing cadence. repeat: Press the keys sequence this many times (1–50). Does not repeat text. wait_for: CSS selector to wait for afterwards, in this same call. wait_for_predicate: JS expression polled until truthy afterwards. wait_until: Readiness signal afterwards — 'none' (default), 'dom_settled' (wait for the DOM to stop changing; prefer this over a fixed sleep), 'networkidle', 'load', 'domcontentloaded', 'settle'.

workspace_writeA

Type text into a Google Workspace editor (Docs or Slides) reliably.

Google Docs/Slides render on , so fill_field/click can't place text and execCommand is deprecated/flaky. This tool dismisses blocking side panels, focuses the editor, and types with real keystrokes (the events the canvas editor actually listens for), then verifies.

Docs: types at the current cursor (auto-removes the Gemini overlay and focuses the hidden input iframe). Slides: pass placeholder=N to pick the text box (0 = first, usually the title). Removes the onboarding modal, double-clicks the placeholder to enter edit mode, then types. Use workspace_new_slide() to add slides.

Newlines in text are sent as real Enter presses.

Args: text: Text to type. target: 'auto' (detect from URL), or force 'docs' / 'slides'. verify: Read the text back to confirm it landed (Docs only, best-effort). placeholder: Slides only — which text placeholder to edit (0-based, in document order; 0 is typically the title).

workspace_new_slideA

Add a new slide in Google Slides (equivalent to Ctrl+M).

Drops the pointer-events lock first so the toolbar is clickable, clicks the 'New slide' button, and settles. Then call workspace_write(target='slides', placeholder=N) to fill the new slide.

submit_formA

Submit a form by clicking a submit button or pressing Enter.

Args: selector: CSS selector of the submit button or form. If omitted, presses Enter on the focused element.

get_page_infoA

Return the current page URL, title, and visible text snippet.

Useful for orientation — call this to confirm where the browser is.

wait_for_elementA

Wait for an element to reach a given state on the page.

Useful after an action that triggers async loading, modal opening, or element removal. Returns ok once the condition is met.

Args: selector: CSS selector for the element to watch. timeout_ms: Maximum time to wait in milliseconds (default 10 000). state: One of: 'visible' — element exists and is visible (default) 'hidden' — element exists but is hidden, or does not exist 'attached' — element is in the DOM (may be hidden) 'detached' — element has been removed from the DOM

wait_for_urlA

Wait for the page URL to contain a given substring.

Use this after clicking a SPA navigation link where the URL changes client-side without a full page reload. Returns once the URL matches or the timeout expires.

Args: url_contains: Substring the URL must contain (e.g. '/dashboard', '?tab=posts'). timeout_ms: Maximum time to wait in milliseconds (default 10 000).

wait_for_predicateA

Wait until a JavaScript expression returns a truthy value.

The general-purpose wait, for when readiness is not "an element appeared": a list reached a length, a spinner class was removed, a global got populated, an animation finished.

wait_for_predicate("document.querySelectorAll('.row').length > 10")
wait_for_predicate("!document.querySelector('.spinner')")
wait_for_predicate("window.__APP_READY === true")

Always prefer this to a fixed sleep — it returns the moment the condition holds, instead of costing the full delay every time. If you only need to wait after a click or a keypress, pass wait_for_predicate to that tool instead and save the extra round-trip.

Args: js: JavaScript expression (or zero-argument function) re-evaluated in page context until it returns truthy. timeout_ms: Maximum time to wait (default 10 000). poll_ms: How often to re-evaluate, in milliseconds (default 100).

evaluateA

Run JavaScript in the page context and return the result.

Use this to handle situations standard selectors can't reach:

  • Shadow DOM: document.querySelector('my-el').shadowRoot.querySelector('input')

  • Iframes: document.querySelector('iframe').contentDocument.querySelector('p')

  • Hidden data: window.INITIAL_DATA or JSON.parse(document.getElementById('NEXT_DATA').textContent)

  • Visibility checks: document.querySelector('.modal')?.getBoundingClientRect()

  • Triggering events: document.querySelector('input').dispatchEvent(new Event('focus'))

Args: js: JavaScript expression to evaluate. The return value is JSON-serialised and included in the response. Keep expressions simple — complex logic is better split across multiple calls.

close_browserA

Close the tab and disconnect from the browser.

In CDP mode (connected to your existing Chrome): closes the tab the agent opened and disconnects. Chrome itself stays running with all your other tabs.

In standard mode: saves the session (if named) and closes the browser.

safety_statusA

What this Bridge is currently allowed to do.

Call it first when an action is refused, or before planning anything that changes data. The limits are set outside the agent and cannot be changed from here — knowing them up front beats discovering them one failure at a time.

Reports read-only mode, the confirmation level, any site allow/deny lists, and where the audit log is written.

account_infoA

Check your Web Speed API credit balance and account status.

Prompts

Interactive templates invoked by user choice

NameDescription

No prompts

Resources

Contextual data attached and managed by the client

NameDescription

No resources

TDQS

A4.2/5.0

Scored across 24 tools

Disambiguation4/5

Tools largely target distinct actions (navigate, click, fill_field, hover, scroll, select_option), and the wait tools are separated by what they wait for (element vs predicate vs URL). Minor overlaps exist—submit_form can be achieved with click or press_keys, and login overlaps with fill_field+submit_form—but descriptions clearly delineate these cases.

Naming Consistency5/5

All tool names use consistent snake_case with verb-first semantics (store_credential, fill_field, wait_for_url, get_page_info, close_browser). Single-word verbs like navigate/click/hover/scroll remain within the same predictable style, so the surface reads uniformly.

Tool Count4/5

24 tools is on the heavier side for the rubric, but browser automation inherently spans navigation, interaction, waiting, credential management, browser lifecycle, and Workspace editing—each tool does appear to earn its place. No obvious redundant tools, so it lands slightly over rather than bloated.

Completeness4/5

The surface covers a full lifecycle: browser setup/open/close, navigation, interaction, multiple wait primitives, form handling, page reading, JS evaluation, and credential storage. Gaps like screenshots, tab/window management, and file upload/download exist but are workable around, especially via evaluate.

Maintenance

ActivityMaintained
ResponsivenessNo issues