> ## Documentation Index
> Fetch the complete documentation index at: https://docs.universalbench.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Tools

> Every input field on the three UniversalBench tools, organised by tool and domain.

UniversalBench exposes three MCP tools. `ub_read` handles read-only work using your own credentials. `ub_write` handles code execution and state-modifying operations. `ub_ai` handles AI and live web capabilities. Set one or more fields per call within each tool.

***

## ub\_read

Read-only operations using your own credentials. Includes database queries, file access, repository reads, and source validation.

UniversalBench can connect to any PostgreSQL-compatible database. Provide your database URL and key via the secrets vault and the database inputs auto-inject them.

### db\_select

Structured query with filters, ordering, and limit. The idiomatic read API.

```json theme={null}
{
  "name": "ub_read",
  "arguments": {
    "db_select": {
      "table": "orders",
      "filters": [["status", "eq", "shipped"], ["created_at", "gte", "2026-01-01"]],
      "order": "-created_at",
      "limit": 50,
      "select": "id,total,customer_id"
    }
  }
}
```

Filter operators include `eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `like`, `ilike`, `in_`. Order strings prefix `-` for descending. Select picks specific columns or `*` for all.

### db\_query

Best effort SQL parse for `SELECT ... FROM tbl [WHERE ...] [ORDER BY ...] [LIMIT N]`. Convenient when your AI already wrote the SQL.

```json theme={null}
{
  "name": "ub_read",
  "arguments": {
    "db_query": "SELECT id, email FROM customers WHERE tier = 'pro' LIMIT 20"
  }
}
```

For anything beyond plain SELECT, prefer `db_select` for filters and `ub_write code` for joins or aggregations.

### db\_search

Case insensitive keyword search across one or more text columns.

```json theme={null}
{
  "name": "ub_read",
  "arguments": {
    "db_search": {
      "table": "knowledge_base",
      "columns": ["title", "body"],
      "query": "refund policy"
    }
  }
}
```

### file\_read

Read a file from the workbench filesystem. Returns the file content as text.

```json theme={null}
{ "name": "ub_read", "arguments": { "file_read": "/tmp/data.csv" } }
```

Files must be under `/tmp`. Files written by `ub_write code` calls in the same session persist for that session.

### git\_read

Read a file from a GitHub repository. Returns content and the file SHA. Works on private repositories.

```json theme={null}
{
  "name": "ub_read",
  "arguments": {
    "git_read": {
      "owner": "your-org",
      "repo": "your-repo",
      "path": "src/index.js",
      "ref": "main"
    }
  }
}
```

Provide `GITHUB_TOKEN` via the secrets vault and it auto-injects into every `git_read` call.

### validate\_file

Static check on Python source. Returns an issues list and, where possible, a fixed version.

```json theme={null}
{ "name": "ub_read", "arguments": { "validate_file": "import os\ndef foo():\n  return os.path.exsts('/tmp')" } }
```

### session\_id

Pass a session identifier to share warm session state with `ub_write` calls using the same ID.

```json theme={null}
{
  "name": "ub_read",
  "arguments": {
    "session_id": "my_pipeline",
    "file_read": "/tmp/data.csv"
  }
}
```

### google\_ads\_research

Read a connected Google Ads account: keyword ideas with monthly search volume and competition, whether your live ads are approved, performance reports (per campaign, per search term, per keyword), the structure of your campaigns and ad groups, and your conversion actions.

Pass a plain keyword string for quick ideas, or an object with an `operation`. Operations: `keyword_research`, `status`, `accounts`, `report_campaigns`, `report_search_terms`, `report_keywords`, `structure`, `conversion_actions`. Reports accept a `date_range` such as `LAST_7_DAYS` or `LAST_30_DAYS`, or explicit `start_date` and `end_date`.

Quick keyword ideas:

```json theme={null}
{ "name": "ub_read", "arguments": { "google_ads_research": "running shoes" } }
```

Read the account structure to get campaign, ad group, and keyword resource names:

```json theme={null}
{ "name": "ub_read", "arguments": { "google_ads_research": { "operation": "structure" } } }
```

A last-7-days campaign performance report:

```json theme={null}
{ "name": "ub_read", "arguments": { "google_ads_research": { "operation": "report_campaigns", "date_range": "LAST_7_DAYS" } } }
```

If the account has not connected Google Ads access yet, the reply returns a connect link.

***

## ub\_write

Code execution and state-modifying operations. Runs in an isolated sandbox. Includes compute, file writes, database writes, GitHub operations, secrets management, and outbound HTTP.

### code

Run Python in a sandboxed environment. Returns stdout, stderr, and execution time.

```json theme={null}
{
  "name": "ub_write",
  "arguments": {
    "code": "import math; print(math.pi * 2)"
  }
}
```

The sandbox includes the Python standard library, common scientific packages (`requests`, `pandas`, `numpy`, etc.), and any packages you install via `install_packages`. The execution timeout is 60 seconds.

### bash

Run a shell command. Returns stdout and stderr.

```json theme={null}
{ "name": "ub_write", "arguments": { "bash": "ls -la /tmp" } }
```

The working directory is `/tmp`. Most standard Linux utilities are available. The execution timeout is 60 seconds.

### parallel\_blocks

Run up to eight code blocks concurrently in one call. Returns a list of results in input order.

```json theme={null}
{
  "name": "ub_write",
  "arguments": {
    "parallel_blocks": [
      { "code": "import time; time.sleep(1); print('one')" },
      { "code": "import time; time.sleep(1); print('two')" },
      { "code": "import time; time.sleep(1); print('three')" }
    ]
  }
}
```

Three blocks that each sleep one second take one second total, not three. Useful for independent fetches, parallel data analysis, or fan out queries.

### install\_packages

Install Python packages before the call. Returns the install log.

```json theme={null}
{
  "name": "ub_write",
  "arguments": {
    "install_packages": ["beautifulsoup4", "lxml"],
    "code": "from bs4 import BeautifulSoup; print('installed')"
  }
}
```

Installed packages persist for the duration of the session. Common packages are already preinstalled and do not need to be listed.

### file\_write

Write a file to the workbench filesystem.

```json theme={null}
{
  "name": "ub_write",
  "arguments": {
    "file_write": {
      "path": "/tmp/output.json",
      "content": "{\"status\": \"ok\"}"
    }
  }
}
```

Paths must be under `/tmp`. Combine with `session_id` to keep written files available for the next call in the same session.

### db\_write

Insert one row, or update rows matching a filter.

```json theme={null}
{
  "name": "ub_write",
  "arguments": {
    "db_write": {
      "table": "events",
      "row": { "type": "signup", "email": "new@example.com" }
    }
  }
}
```

```json theme={null}
{
  "name": "ub_write",
  "arguments": {
    "db_write": {
      "table": "customers",
      "filter": [["id", "eq", "cust_123"]],
      "update": { "tier": "pro" }
    }
  }
}
```

### db\_upsert

Upsert one row using one or more conflict columns.

```json theme={null}
{
  "name": "ub_write",
  "arguments": {
    "db_upsert": {
      "table": "customer_state",
      "row": { "customer_id": "cust_123", "last_seen_at": "2026-05-17T10:00:00Z" },
      "on_conflict": "customer_id"
    }
  }
}
```

### git\_push

Push a file to GitHub. Returns the commit SHA on success.

```json theme={null}
{
  "name": "ub_write",
  "arguments": {
    "git_push": {
      "owner": "your-org",
      "repo": "your-repo",
      "path": "src/index.js",
      "content": "// new file content",
      "message": "feat: add new module",
      "branch": "main",
      "sha": "abc123def456"
    }
  }
}
```

For `.py` files, Python is validated before the push lands. Files that would crash at runtime are rejected before they reach your repository. Your AI cannot ship broken Python through UniversalBench.

### code\_diff

Run two code blocks and compare their outputs. Useful for verifying that a refactor did not change behaviour.

```json theme={null}
{
  "name": "ub_write",
  "arguments": {
    "code_diff": {
      "old_code": "def f(x): return x*2",
      "new_code": "def f(x): return x+x"
    }
  }
}
```

Returns the output diff if the two diverge on the same inputs.

### code\_edit

Single anchor find and replace on a file. Pass the old text and the new text. Ambiguous matches are rejected.

```json theme={null}
{
  "name": "ub_write",
  "arguments": {
    "code_edit": {
      "path": "/tmp/script.py",
      "old": "TIMEOUT = 30",
      "new": "TIMEOUT = 60"
    }
  }
}
```

When the anchor appears more than once, the edit is rejected with the count rather than silently editing the wrong place.

### safe\_deploy

Push a file and run a smoke test against a URL after the push lands. If the smoke test fails, the push is rolled back automatically.

```json theme={null}
{
  "name": "ub_write",
  "arguments": {
    "safe_deploy": {
      "owner": "your-org",
      "repo": "your-repo",
      "path": "src/index.js",
      "content": "// new content",
      "message": "feat: ship new feature",
      "smoke_test_url": "https://your-app.com/health"
    }
  }
}
```

### proxy\_http

Make an outbound HTTP call from the workbench. Returns status, headers, body, and bytes received.

```json theme={null}
{
  "name": "ub_write",
  "arguments": {
    "proxy_http": {
      "method": "GET",
      "url": "https://api.github.com/repos/octocat/Hello-World",
      "headers": { "Accept": "application/vnd.github+json" },
      "timeout": 15
    }
  }
}
```

Only `http` and `https` schemes are accepted. Internal network addresses and cloud metadata endpoints are blocked to prevent server side request forgery. Response bodies above a fixed cap are truncated and flagged in the response.

### secrets\_vault

Encrypted per customer secret storage. Values are encrypted at rest. Your AI references secrets by name, never by value.

<Note>
  The action is `save` (not `set` or `store`), the name field is `secret_name` (not `key` or `name`), and the value field is `secret_value` (not `value`). Getting one of these wrong is the most common vault error. See [Troubleshooting](/troubleshooting#secrets-vault-says-my-field-is-missing-or-the-action-is-invalid).
</Note>

Save a secret:

```json theme={null}
{
  "name": "ub_write",
  "arguments": {
    "secrets_vault": {
      "action": "save",
      "secret_name": "STRIPE_KEY",
      "secret_value": "sk_live_xxx"
    }
  }
}
```

List secret names (values are never returned):

```json theme={null}
{ "name": "ub_write", "arguments": { "secrets_vault": { "action": "list" } } }
```

Retrieve a secret value:

```json theme={null}
{ "name": "ub_write", "arguments": { "secrets_vault": { "action": "get", "secret_name": "STRIPE_KEY" } } }
```

Delete a secret permanently:

```json theme={null}
{ "name": "ub_write", "arguments": { "secrets_vault": { "action": "delete", "secret_name": "OLD_KEY" } } }
```

Secrets are scoped to your account. Other customers cannot read them. Common credentials like `SUPABASE_URL`, `SUPABASE_KEY`, and `GITHUB_TOKEN` are auto-injected into matching tools so your AI never needs to read the value.

### session\_id and clear\_session

Pass `session_id` to keep Python variables, imports, and connections warm across calls:

```json theme={null}
{
  "name": "ub_write",
  "arguments": {
    "session_id": "my_pipeline",
    "code": "import pandas as pd; df = pd.read_csv('/tmp/data.csv')"
  }
}
```

Subsequent calls with the same `session_id` can reference `df` and `pd` without redoing the work. Sessions expire after a period of inactivity.

Pass `clear_session: true` to wipe all state before processing the call:

```json theme={null}
{
  "name": "ub_write",
  "arguments": {
    "session_id": "my_pipeline",
    "clear_session": true,
    "code": "print('fresh session')"
  }
}
```

### task

Optional. A natural-language description of what this call is doing. Used for telemetry and adaptive timeout tuning only. Has no effect on execution.

```json theme={null}
{
  "name": "ub_write",
  "arguments": {
    "task": "build month-over-month revenue chart",
    "code": "..."
  }
}
```

### Combining inputs

You can set multiple input fields in one `ub_write` call:

```json theme={null}
{
  "name": "ub_write",
  "arguments": {
    "install_packages": ["yfinance"],
    "code": "import yfinance as yf; print(yf.Ticker('AAPL').info['currentPrice'])"
  }
}
```

This installs `yfinance` and runs the code in one call, billed as one call.

### google\_ads

Manage a connected Google Ads account end to end. Build campaigns, ad groups, keywords, and responsive search ads, upload image assets, and add a video ad. Set targeting: locations and proximity, ad schedules, languages, device bid adjustments, and audiences. Set bidding (manual CPC, maximize conversions, maximize conversion value, target CPA, target ROAS, maximize clicks) and budgets. Add ad extensions: sitelinks, callouts, structured snippets, call extensions, promotions, and prices. Set up conversion tracking, which returns the tracking snippet to install on your site. Edit a live account: pause or launch campaigns, ad groups, and keywords, change budgets and bids, add negative keywords, and remove items.

<Note>
  New entities are created paused, so nothing spends until you launch it. Any change that can spend money or remove something (launching or enabling anything, raising a budget, changing the bidding strategy, removing an item) returns a short approval request describing the exact change. Relay it to the user, then call again with `confirm` set to `once` to do it this time, or `always` to allow that kind of change for this account from now on. Every change is recorded.
</Note>

Pass an object with an `operation`. Build: `create_campaign`, `create_ad_group`, `add_keywords`, `create_rsa`, `upload_image_asset`, `create_video_ad`. Targeting: `add_geo_target`, `add_ad_schedule`, `set_language_target`, `set_device_bid_modifier`, `add_audience`. Bidding and budget: `set_bidding_strategy`, `update_campaign_budget`. Extensions: `create_sitelink`, `create_callout`, `create_structured_snippet`, `create_call_extension`, `create_promotion`, `create_price`. Conversion tracking: `create_conversion_action`. Manage: `update_campaign_status`, `update_ad_group_status`, `update_ad_group_bid`, `update_keyword_status`, `update_keyword_bid`, `add_negative_keywords`, `remove_campaign`, `remove_ad_group`, `remove_keyword`, `remove_ad`.

<Tip>
  All money is in micros: multiply the currency amount by 1,000,000, so 50 units is `50000000`. Get campaign, ad group, and keyword resource names from `google_ads_research` with the `structure` operation first. If a change is rejected, the reply tells you exactly what to fix and what to read, so relay that and retry. For the exact fields of any operation, call `how_to` on ub\_read with the name `google_ads`.
</Tip>

Create a campaign (created paused, nothing spends):

```json theme={null}
{ "name": "ub_write", "arguments": { "google_ads": { "operation": "create_campaign", "name": "Spring Sale", "daily_budget_micros": 50000000 } } }
```

Launch a campaign (spend-affecting, needs approval):

```json theme={null}
{ "name": "ub_write", "arguments": { "google_ads": { "operation": "update_campaign_status", "campaign": "1234567890", "status": "ENABLED", "confirm": "once" } } }
```

Set a bidding strategy:

```json theme={null}
{ "name": "ub_write", "arguments": { "google_ads": { "operation": "set_bidding_strategy", "campaign": "1234567890", "strategy": "target_cpa", "target_cpa_micros": 25000000, "confirm": "once" } } }
```

Set up conversion tracking (returns the snippet to install on your site):

```json theme={null}
{ "name": "ub_write", "arguments": { "google_ads": { "operation": "create_conversion_action", "name": "Purchase" } } }
```

***

## ub\_ai

AI and live web capabilities. Each `ub_ai` call incurs an additional provider cost on top of the base per-call rate.

### web\_search

Search the web for live results. Returns the top five results with title, snippet, and URL.

```json theme={null}
{ "name": "ub_ai", "arguments": { "web_search": "latest GPT model releases" } }
```

Results are real time and include source URLs.

### invoke\_llm

Call any major LLM. A prompt string goes in, the completion string comes out.

```json theme={null}
{ "name": "ub_ai", "arguments": { "invoke_llm": "Write a haiku about distributed systems" } }
```

The default model is a cost-efficient one. To route to a specific model, prefix your prompt with `model=<name>;`, for example `model=claude-3-5-sonnet; Write a haiku...`. Your AI platform's tool description lists available model identifiers.

***

## Database setup

Connect to any PostgreSQL-compatible database. Save your database URL and key as named secrets via `secrets_vault`. Name them `SUPABASE_URL` and `SUPABASE_KEY` and they auto-inject on every call.

## GitHub setup

Save a personal access token in `secrets_vault` under the name `GITHUB_TOKEN`. The `git_read`, `git_push`, `code_edit`, and `safe_deploy` fields auto-inject it on every call.

<Warning>
  The name must be `GITHUB_TOKEN`. If you save the token under another name such as `GIT_PAT` or with a typo, the GitHub fields cannot find it and every `git_*` call fails. If that happens, see [Troubleshooting](/troubleshooting#git-read-or-git-push-fails-even-though-i-saved-my-token).
</Warning>
