---
product: "AG Studio"
title: "External Tools"
description: "Learn how to declare tools that something else runs: your own server, or the LLM provider itself."
framework: vue
version: "3.0.0"
related:
    - title: "Tools Overview"
      url: "https://www.ag-grid.com/studio/archive/3.0.0/vue/ai-tools/"
    - title: "Built-in Tools"
      url: "https://www.ag-grid.com/studio/archive/3.0.0/vue/ai-tools-builtin/"
    - title: "Custom Tools"
      url: "https://www.ag-grid.com/studio/archive/3.0.0/vue/ai-custom-tools/"
llms: "https://www.ag-grid.com/studio/archive/3.0.0/llms.txt"
---

# External Tools

Not every tool an agent can call runs in the browser. A tool declares *where* it executes with `kind`:

| `kind` | Who runs it | Studio's part |
| --- | --- | --- |
| `client` (default) | Studio, in the page | Advertises the schema and executes it |
| `server` | The agent's own harness | Advertises the schema only |
| `provided` | The LLM provider | Passes the provider's declaration through |

Only `client` tools have an `execute`. The other two are declared here and run elsewhere.

## Server Tools

Use `kind: 'server'` when the *client* should advertise a schema that your *server* executes. That is a narrow case:

- If your agent runs [its own loop](https://www.ag-grid.com/studio/archive/3.0.0/vue/ai-custom-runner/) and the server owns a tool entirely, the server declares it and Studio never sees it. You need nothing here.
- If the client is the one that knows the schema, because it depends on live dashboard state, but the work must happen server-side, declare it here.

```ts
const lookupCustomer = api.defineAiTool({
    kind: 'server',
    name: 'lookup_customer',
    description: 'Fetch a customer record from the CRM.',
    params: (s) => s.object({ customerId: s.string({ description: 'CRM customer id.' }) }),
});
```

Studio advertises the schema to the model. When the model calls it, Studio executes nothing and returns a placeholder response in its place, so the loop keeps moving and your harness can do the work.

## Provider Tools

Some providers host tools themselves - web search, code execution, file retrieval. These are never called back to your code: the provider runs them inside the same request and returns the result.

Declare one with `kind: 'provided'` and hand over the provider's own declaration:

```ts
const webSearch = api.defineAiTool({
    kind: 'provided',
    name: 'web_search',
    description: 'Search the web for current information.',
    provider: { type: 'web_search' },
});
```

`provider` is opaque to Studio. It is attached to the tool's schema as-is and reaches your adapter, which turns it into whatever the provider expects - see [Tool Calls](https://www.ag-grid.com/studio/archive/3.0.0/vue/ai-direct-llm-runner/#tool-calls).

Because the shape is provider-specific, a `provided` tool ties that agent to that provider. Keep the declaration next to the adapter it belongs with.

A provider-side tool your adapter injects without Studio knowing about it needs no declaration at all, and never appears in a Studio tool list. Declare it only when you want it visible alongside the rest, in the panel's message list and in the telemetry stream.

## Listing Them

External tools are listed exactly like any other:

```ts
directLlmRunner({
    id: 'analyst',
    adapter,
    tools: () => [studio.viewSchema(), studio.executeQuery(), lookupCustomer, webSearch],
});
```

## Next

- [Direct LLM Runner](https://www.ag-grid.com/studio/archive/3.0.0/vue/ai-direct-llm-runner/) - where a provider tool's declaration is translated
- [Client Tool Runner](https://www.ag-grid.com/studio/archive/3.0.0/vue/ai-client-tool-runner/) - when the loop runs on your server
- [Custom Tools](https://www.ag-grid.com/studio/archive/3.0.0/vue/ai-custom-tools/) - client tools
