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.
The SQL toolsets expose read-oriented query surfaces. The Supabase connector also exposes writes, auth administration, storage mutations and function calls. Use database credentials restricted to the intended operations: parser checks and registration tags do not replace database permissions.
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 response-local 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. The max_results argument caps each list (default 25). sample_table defaults to 5 rows so quick lookups stay tidy. The read-only safety checks include parser denylists and engine-specific restrictions. A permitted SELECT can still call a function with side effects; use a restricted database role.
#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 Agent
from maivn_tools import SQLiteToolSet, register_connector
connector = SQLiteToolSet("./reports.db", row_limit=500)
agent = Agent(name="database-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, and PRAGMA. Identifier-taking tools validate name against [A-Za-z_][A-Za-z0-9_]* so the underlying PRAGMA calls cannot be hijacked.
#Agent-ready behavior
list_tables,list_views, andlist_indexesreturn envelopes with ordinaltable_ref/view_ref/index_refplus user-facingnameand (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_keyfields 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=False),
)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 attempts SET TRANSACTION READ ONLY per call, but catches failures from that statement. Do not assume it established read-only mode. Custom factories should use transactions rather than autocommit and a database role without write rights. explain_query refuses analyze=True because EXPLAIN ANALYZE executes the underlying query and may have side effects.
#Agent-ready behavior
list_schemas,list_tables,list_views, andlist_indexesreturn 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 -- pass connection_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 INDEXEScolumns 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_viewsreturn 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 display 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": "..."})