Tools & Connectors
Databases
SQLite, Postgres, MySQL, SQL Server, and Supabase toolsets.
#Databases
Transactional database connectors. Each toolset gives an agent
read-only schema introspection and parameterized query tools over one
database engine. For analytics warehouses see
Warehouses.
Every connector follows the standard @toolset / @toolify shape and
defaults to read-only -- writes (and write-style SQL) are rejected
either at the parser or with SET TRANSACTION READ ONLY / PRAGMA query_only. Use add_toolset(..., include_tags=["read"]) to drop any
write surface a connector exposes.
All five connectors in this group follow the same agent-ready pattern
for catalog tools: list_schemas, list_tables, list_views,list_indexes, and list_databases return a summary envelope
({<key>, returned, total, truncated}) where each entry carries a
stable ordinal ref (schema_ref, table_ref, view_ref, index_ref,database_ref) plus the user-facing schema / table / view / column /
index names. Those names are always present -- the connector never hides
identifiers an agent needs to compose a follow-up query. Themax_results argument caps each list (default 25). sample_table
defaults to 5 rows so quick lookups stay tidy. The read-only safety
guarantees still apply: parser denylists, PRAGMA query_only,SET TRANSACTION READ ONLY, and identifier validation prevent
accidental writes.
#SQLiteToolSet
SQLiteToolSet exposes read-only schema introspection and parameterized
query tools over a local SQLite database file. It is dependency-free
(uses the standard-library sqlite3 module) and opens a fresh
connection per call so the connector is safe to share across threads.
from maivn import Agentfrom maivn_tools import SQLiteToolSet, register_connector connector = SQLiteToolSet("./reports.db", row_limit=500)agent = Agent(model="auto")register_connector(agent, connector)Tools: list_tables(include_views, max_results),list_views(max_results), list_indexes(table=None, max_results),list_foreign_keys(table), describe_table(name), get_schema_dump(),sample_table(name, limit), count_rows(name),explain_query(sql, plan), run_query(sql, parameters, row_limit).
run_query only accepts SELECT, WITH, and EXPLAIN. Compound
statements (multiple semicolons) are rejected, and a regex denylist
blocks INSERT, UPDATE, DELETE, DROP, ALTER, CREATE,REPLACE, TRUNCATE, ATTACH, DETACH, VACUUM, REINDEX, andPRAGMA. Identifier-taking tools validate name against[A-Za-z_][A-Za-z0-9_]* so the underlying PRAGMA calls cannot be
hijacked.
| Argument | Default | Purpose |
|---|---|---|
database |
required | Path to the SQLite file, or ":memory:". |
row_limit |
500 |
Maximum rows returned per query. |
query_timeout_seconds |
5.0 |
SQLite busy timeout. |
#Agent-ready behavior
list_tables,list_views, andlist_indexesreturn envelopes with
ordinaltable_ref/view_ref/index_refplus user-facingname
and (for indexes / views) the DDLsql. Internalsqlite_*objects
are always filtered out.describe_tablereturns column metadata, primary keys, and indexes --
the columnname/type/notnull/default/primary_key
fields a SELECT needs.sample_table(name)defaults to 5 rows; raiselimit(capped by
the connectorrow_limit) when you need more.run_querydefaults to 100 rows per call; raiserow_limitper
call up to the configured connector ceiling.- No write tools --
SQLiteToolSetis read-only by design.
Example:
tables = connector.list_tables()# {"tables": [{"table_ref": "table_1", "name": "orders", "type": "table"}, ...], "returned": 25, "total": 47, "truncated": True}sample = connector.sample_table(tables["tables"][0]["name"])# {"columns": ["id", "customer_id", ...], "rows": [{"id": 1, ...}, ...], "row_count": 5, "truncated": True}#PostgresToolSet
PostgresToolSet exposes read-only schema introspection and query tools
over a PostgreSQL database. The connector wraps any DB-API 2.0 driver
behind a small connection-factory protocol so tests can inject fakes
and so the base package does not require psycopg to be installed.
from maivn_tools import PostgresToolSet connector = PostgresToolSet( dsn="postgresql://reader:password@localhost:5432/analytics", row_limit=500,)If psycopg is not installed the connector falls back to psycopg2.
To use a different driver, supply a connection_factory:
import psycopg connector = PostgresToolSet( connection_factory=lambda: psycopg.connect(dsn, autocommit=True),)Tools: list_schemas(max_results), list_tables(schema, max_results),list_views(schema, max_results),list_indexes(schema, table=None, max_results),list_foreign_keys(name, schema), list_extensions(),describe_table(name, schema), get_table_size(name, schema),sample_table(name, schema, limit), count_rows(name, schema),server_version(), explain_query(sql, analyze, verbose),run_query(sql, parameters, row_limit).
run_query only accepts SELECT, WITH, and EXPLAIN. The connector
issues SET TRANSACTION READ ONLY per call (drivers that do not support
it are silently ignored), so even if a query somehow bypasses the regex,
the database itself refuses writes. explain_query refusesanalyze=True because EXPLAIN ANALYZE executes the underlying query
and may have side effects.
| Argument | Default | Purpose |
|---|---|---|
dsn |
None | Connection string used by the default factory. |
connection_factory |
None | Custom DB-API factory; mutually exclusive with dsn. |
row_limit |
500 |
Maximum rows returned per query. |
#Agent-ready behavior
list_schemas,list_tables,list_views, andlist_indexes
return envelopes with ordinal refs (schema_ref,table_ref,view_ref,index_ref) plus the user-facingschema/name/typecolumns. Defaultmax_resultsis 25.describe_tablereturns{"name", "schema", "columns", "primary_key"}
--columns[*]carriesname,type,nullable,default.sample_table(name)defaults to 5 rows.run_querydefaults to 100 rows per call; raiserow_limitper
call up to the configured ceiling.
Example:
tables = connector.list_tables(schema="public")# {"tables": [{"table_ref": "table_1", "schema": "public", "name": "orders", "type": "BASE TABLE"}, ...], ...}#MySQLToolSet
MySQLToolSet is a read-only DB-API 2.0 connector for MySQL and
MariaDB, mirroring PostgresToolSet. The driver
(mysql-connector-python or pymysql) is not a hard dependency -- passconnection_factory or install one of the supported drivers.
from maivn_tools import MySQLToolSet connector = MySQLToolSet(connect_kwargs={ "host": "db.example.com", "user": "reader", "password": secrets["MYSQL_PASSWORD"], "database": "analytics",})Tools: list_databases(max_results),list_tables(schema, max_results), describe_table(name, schema),list_indexes(name, schema, max_results),explain_query(sql, analyze), server_version(),sample_table(name, schema, limit), count_rows(name, schema),run_query(sql, parameters, row_limit).
run_query only accepts statements whose first keyword is SELECT,WITH, EXPLAIN, DESCRIBE, DESC, or SHOW. Compound statements
and a denylist of mutation keywords are rejected.
#Agent-ready behavior
list_databases,list_tables, andlist_indexesreturn envelopes
withdatabase_ref/table_ref/index_refplus the user-facing
MySQL column names (Database,name,type, plusSHOW INDEXES
columns likeKey_name,Column_name,Non_unique). Defaultmax_resultsis 25.describe_tablereturns{"schema", "name", "columns", "primary_key"}
with the MySQL columnkeyflag (PRI,MUL, ...).sample_table(name)defaults to 5 rows.run_querydefaults to 100 rows per call.
#SQLServerToolSet
SQLServerToolSet is a read-only DB-API 2.0 connector for Microsoft
SQL Server. Pass connection_string to use pyodbc, connect_kwargs
to use pymssql, or a custom connection_factory for tests.
from maivn_tools import SQLServerToolSet connector = SQLServerToolSet(connection_string="DRIVER=ODBC Driver 18 ...")Tools: list_databases(max_results), list_schemas(max_results),list_tables(schema="dbo", max_results),describe_table(name, schema="dbo"),list_views(schema="dbo", max_results), server_version(),sample_table(name, schema, limit), count_rows(name, schema),run_query(sql, parameters, row_limit).
run_query accepts only SELECT and WITH statements; compound
statements and a denylist of mutation keywords (including EXEC /EXECUTE / MERGE) are rejected.
#Agent-ready behavior
list_databases,list_schemas,list_tables, andlist_views
return envelopes with ordinal refs plus user-facingname/schema
/typecolumns. Defaultmax_resultsis 25.describe_tablereturns{"schema", "name", "columns", "primary_key"}.sample_table(name)defaults to 5 rows and usesSELECT TOP.run_querydefaults to 100 rows per call.
#SupabaseToolSet
SupabaseToolSet is a single connector spanning Supabase Platform's
public surfaces: PostgREST data access (incl. RPC and pgvector
matching), GoTrue auth admin, Storage objects, and Edge Functions.
Authentication uses the project's anon or service_role key (passed
as apikey) plus an optional separate access token for end-user
impersonation.
from maivn_tools import SupabaseToolSet connector = SupabaseToolSet( project_url="https://abcd.supabase.co", api_key=secrets["SUPABASE_SERVICE_ROLE"],)Service-role keys grant unrestricted access; treat them as
destructive credentials.
PostgREST data tools: select(table, ...), insert(table, rows, ...),update(table, filter, values, ...), delete(table, filter, ...)
(destructive), rpc(function_name, args, ...),match_vectors(function_name, embedding, ...).
Auth admin tools: list_users(include_metadata, include_ids),get_user(user_id), create_user(...), update_user(user_id, fields),delete_user(user_id) (destructive), invite_user(email, ...).
Storage tools: list_buckets(include_metadata), create_bucket(...),delete_bucket(bucket_id) (destructive),list_objects(bucket_id, include_metadata, ...),create_signed_url(bucket_id, path, ...),delete_object(bucket_id, path) (destructive).
Edge Functions: invoke_function(function_name, body, ...).
#Agent-ready behavior
list_users,list_buckets, andlist_objectsreturn compact
summaries by default with stable refs (user_ref,bucket_ref,object_ref). User-facing fields always shown: useremail/phone/role, bucketname, objectname(the bucket-relative
path),size,content_type. Passinclude_metadata=Falsefor the
raw GoTrue / Supabase response.- For
list_users, raw UUIDs are hidden by default -- setinclude_ids=Trueto exposeuser_id.update_user,delete_user,
andget_useraccept either the raw UUID string or the dict fromlist_users(include_ids=True). list_buckets/list_objectsalways show the bucket / object names
(those are the user-facing identifiers -- not internal handles).delete_bucket,delete_object, andcreate_signed_urlaccept
either the raw ID / path string or the dict returned by the
corresponding list.- Default
per_pageforlist_usersis 25; defaultlimitforlist_objectsis 25; default PostgRESTselectlimitis
100. - Destructive tools:
delete(PostgREST row delete),delete_user,delete_bucket,delete_object.deleteandupdaterequire a
non-emptyfilterso a full-table mutation is rejected up front.
Example:
users = connector.list_users()# {"users": [{"user_ref": "user_1", "email": "alice@example.com", "role": "authenticated", ...}, ...], "page": 1, "per_page": 25}users_with_ids = connector.list_users(include_ids=True)connector.update_user(users_with_ids["users"][0], {"banned_until": "..."})