rtrvr.ai agents aren't limited to browsing. They can call external APIs, query databases, and run custom logic using the Model Context Protocol (MCP) or secure JavaScript tools. Tools are a shared primitive — create them once, use them across the extension, cloud, and API.
AI Subroutines
AI Subroutines are reusable tools generated by rtrvr.ai from natural-language intent, recordings, API docs, or the current webpage context. They are ideal when you want a stable capability such as “send a LinkedIn DM”, “create a HubSpot contact”, or “submit this internal form” without rebuilding the workflow each time.
- Generate a subroutine from a natural-language request
- Generate a subroutine from a recording to capture a real interaction flow
- Point the generator at API docs or an authenticated webpage and let it infer the tool shape
- Save the resulting tool once and reuse it from chats, workflows, schedules, and API-triggered runs
Direct Tool Calls
When you know exactly which tool to use, bypass the AI planner with the @toolName syntax. This is highly efficient for repetitive tasks and gives you direct control.
@act(action="click submit") → Direct browser action
@extractToSheets(prompt="get emails") → Fast extraction across open tabs
@hubspot_lookup(email="user@example.com") → Call a custom/MCP tool directlyMCP Servers
Connect to any Model Context Protocol server by pasting its URL. Once connected, all MCP tools become available in your chat with @toolname syntax. rtrvr.ai supports SSE (Server-Sent Events), HTTP Streamable, and OAuth-protected servers.
- Open the Tools section in extension settings
- Paste the MCP server URL (e.g., your company's internal MCP, or a public one)
- Authenticate if required (OAuth flow handled in-browser)
- All server tools appear instantly — use them with @toolname in chat
AI Tool Generator
Don't have an MCP server? The Tool Generator sub-agent can create AI Subroutines automatically. Just describe what you need in plain English — or better yet, point the agent at an API documentation page, an authenticated web app, or a recording and let it build the tool for you.
"Find my HubSpot API keys and create a tool to load contacts"
"Use this onscreen API docs to create a tool that searches our internal database"
"Create a tool that calls the OpenWeatherMap API with a city name and returns the forecast"
"Turn this LinkedIn recording into an AI Subroutine that opens Message, writes a DM, and sends it"Create a Subroutine From a Recording
Recordings are one of the fastest ways to create robust AI Subroutines. rtrvr.ai analyzes the DOM interactions and nearby network traffic, then chooses the best replay strategy: semantic DOM automation when the UI flow is the stable source of truth, or network-backed execution when the captured request is clearly first-party and reusable.
- Record the task once in the extension
- Open the recording and choose to generate a tool/subroutine
- The generator uses the recording as grounding context for buttons, composers, waits, and API shape
- Save the generated tool and call it directly with @toolName or from workflows
Custom JavaScript Tools
Write your own tools in JavaScript or let the AI build them. Subroutines can run as sandboxed JavaScript tools or as webpage tools that execute in the authenticated browser context. You can store API keys as default parameters — they remain local to your machine and are never sent to rtrvr.ai servers.
Two Execution Styles
| Style | Best For | What It Can Access |
|---|---|---|
| Sandbox tool | Pure computation, public APIs, data transforms, authenticated APIs with local API keys | JavaScript runtime, fetch, parameters, defaults |
| Webpage tool / AI Subroutine | Logged-in websites, DOM actions, page cookies, in-page fetch, rich editors, CSRF-protected requests | Authenticated page context plus the `rtrvr` helper namespace |
How Parameters Work
When you define parameters for a custom function, they become available as JavaScript variables in your code. The system automatically converts each parameter into a const declaration before running your code.
// Parameters defined: firstName (string), lastName (string), apiKey (string, default)
// Your code — parameters are pre-declared as const variables:
const res = await fetch(`https://api.example.com/users?name=${firstName}+${lastName}`, {
headers: { "Authorization": `Bearer ${apiKey}` }
});
const data = await res.json();
return data.results;- Define parameters with names, types, and optional defaults
- Reference parameters directly as variables (firstName, not params.firstName)
- Parameters are injected as const declarations before your code runs
- Return any JSON-serializable value — async/await is fully supported
- console.log() output is captured and shown in results for debugging
Code Examples
// Simple greeting
return `Hello ${firstName} ${lastName}!`;
// Math
return price * quantity * (1 + taxRate);
// API call
const r = await fetch(url);
return await r.json();
// Transform
return items.map(i => i.name).join(", ");Parameter names must be valid JavaScript identifiers (letters, numbers, underscores — no spaces).
Webpage Helper Functions (`rtrvr`)
Webpage tools and AI Subroutines can use the built-in `rtrvr` helper namespace to interact with the live page without dropping down to brittle manual DOM code. These helpers are especially useful for authenticated flows, contenteditable editors, CSRF-protected requests, and waiting for UI state transitions.
| Helper | Use |
|---|---|
| `rtrvr.find({ role, name, text, placeholder })` | Find a semantic page target and return an opaque handle |
| `rtrvr.click(handleOrTarget)` | Click a previously found handle or a semantic target |
| `rtrvr.type(handleOrTarget, value, { clear, submit })` | Type into inputs or rich contenteditable editors |
| `rtrvr.waitFor(targetOrFn, { timeoutMs })` | Wait for the next UI state, modal, composer, or control |
| `rtrvr.waitForUrl(match, { timeoutMs })` | Wait for navigation or route changes |
| `rtrvr.request(url, init)` | Make authenticated in-page requests using the page context |
| `rtrvr.requestJson(url, init)` | Same as request, but parses JSON when available |
| `rtrvr.getCsrfToken()` | Read the current page CSRF token for sites that require it |
| `rtrvr.getCookie(name)` | Read a cookie value from the current page |
// Example webpage tool body
const button = await rtrvr.find({
role: "button",
name: /Connect/i,
});
if (!button) {
return { success: false, error: "Connect button not found." };
}
await rtrvr.click(button);
const csrfToken = rtrvr.getCsrfToken();
return await rtrvr.requestJson("/voyager/api/example", {
method: "POST",
headers: {
"content-type": "application/json",
"x-csrf-token": csrfToken,
},
body: JSON.stringify({ ok: true }),
});Choosing DOM vs Network Tools
The best AI Subroutines pick the right execution strategy for the site. In general: use DOM actions when the UI flow is the stable contract, and use network-backed execution when the request itself is the stable contract.
| Prefer DOM Actions When... | Prefer Network Interaction When... |
|---|---|
| The site uses volatile internal APIs, rotating GraphQL IDs, or framework-specific hidden identifiers | You have a clear first-party endpoint with a stable request/response shape |
| You need to click, type, open menus, wait for dialogs, or work inside rich editors | The action is fundamentally an API call and does not depend on visible UI state |
| The only evidence you have is a recording of buttons, composers, and page transitions | You need structured JSON back and the site’s authenticated page context can safely make the request |
- For DOM tools, prefer semantic targets such as role, accessible name, placeholder, and visible text
- Use staged waits after each meaningful action: open dialog → wait for composer → type → wait for send button
- Avoid brittle CSS selectors and volatile class names in generated tools
- For network tools, prefer `rtrvr.request()` / `rtrvr.requestJson()` over copying full captured browser headers
- Never hardcode cookies, bearer tokens, CSRF tokens, or volatile query/operation IDs from a recording
Sheets Tool Mapping
In Sheets Workflows, the agent can map tool calls to run for every row — intelligently pulling arguments from specific columns. Just include instructions in your prompt:
"For each row, use the loadContact tool to upload the email in Column A and name in Column B to HubSpot"| Column A (Email) | Column B (Name) | Column C (Result) |
|---|---|---|
| user@example.com | Jane Doe | ✅ Contact created (ID: 12345) |
| admin@test.org | John Smith | ✅ Contact created (ID: 12346) |
Platform Availability
| Capability | Extension | Cloud | API |
|---|---|---|---|
| @toolname direct calls | ✅ | — | — |
| MCP server connections | ✅ | ✅ | ✅ |
| AI Tool Generator | ✅ | ✅ | — |
| Custom JavaScript tools | ✅ | ✅ | — |
| Sheets tool mapping | ✅ | ✅ | ✅ |
| Tools in replayed workflows | ✅ | ✅ | ✅ |