A SQL tool is a stored, parameterized query that an agent can invoke by name. Use it to give an agent access to your own tables and business logic, without writing any Rust or exposing a native AIDB function:
SELECT aidb.create_sql_tool( name => 'orders_by_customer', description => 'Look up recent orders for a customer by id.', sql_statement => 'SELECT id, status, total FROM orders WHERE customer_id = ${customer_id} ORDER BY created_at DESC LIMIT ${limit}', params => aidb.tool_params( aidb.tool_param('customer_id', 'INT', 'The customer''s id.'), aidb.tool_param('limit', 'INT', 'Maximum number of orders to return.') ), read_only => true, -- optional; enforced, not just descriptive (see below). Default: true return_type_hint => NULL -- optional; documents the returned row shape, same aidb.tool_params() shape as `params`. Default: NULL );
| Parameter | Type | Default | Description |
|---|---|---|---|
name | TEXT | Required | Unique name for the tool. |
description | TEXT | Required | Shown to the model as part of the tool's definition. |
sql_statement | TEXT | Required | The query to run, with ${name} placeholders for each declared parameter. |
params | JSONB | Required | The tool's parameters, built with aidb.tool_params(). |
read_only | BOOLEAN | true | If true, reject the statement at registration time unless it's provably read-only. |
return_type_hint | JSONB | NULL | Documents the query's return shape, in the same aidb.tool_params() shape. Not currently surfaced to the model. |
aidb.tool_param(name, type, description) builds one parameter; aidb.tool_params(...) combines several; aidb.tool_params() with no arguments declares a tool that takes no parameters.
Register the tool on an agent the same way as any other:
SELECT aidb.create_agent('sales_helper', 'Answer questions about customer orders.', 'my_gpt', tools => ARRAY['orders_by_customer']);
Naming
A tool's name must be unique across every tool type — it can't collide with a built-in native tool or a tool already imported from an MCP server. aidb.create_sql_tool() rejects the call up front if it does.
Parameter placeholders
Reference each declared parameter in sql_statement as ${name} — AIDB substitutes each with the value the model supplied for that call, bound as a real query parameter (not string-interpolated). A parameter used more than once in the statement only needs to be declared once. params is required; pass aidb.tool_params() with no arguments for a tool that takes no parameters.
Read-only tools
read_only defaults to true. Pass read_only => false for a tool that needs to write — and that's enforced, not just descriptive, in both directions: left at the default true, registration fails immediately if sql_statement matches a recognized write pattern (INSERT, UPDATE, DELETE, and so on), rather than letting a mislabeled tool through. A tool left at the default read_only => true is also usable by an agent running in read-only mode; a tool explicitly marked read_only => false is excluded from a read-only run, the same as an unclassified native or MCP tool.
sql_statement must be a single statement, and can't be a utility statement like EXPLAIN or COPY. Trailing whitespace and a trailing ; are stripped automatically when you register it.
Note
create_sql_tool also accepts a return_type_hint argument, in the same aidb.tool_params() shape as params, describing the shape of the rows the query returns. It's stored alongside the tool but isn't currently surfaced to the model or to aidb.tools. For now, its only use is as documentation for anyone inspecting aidb.sql_tool_registry directly.
Removing a tool
SELECT aidb.delete_tool('orders_by_customer');
aidb.delete_tool() also removes an MCP server registration if the name you pass belongs to one instead of a SQL tool, but built-in native tools can't be deleted.