Database
Read and write access to SQL databases with privilege separation via separate engines.
DatabaseContextProvider gives agents read/write access to any SQL database via SQLAlchemy. Two tools: query_database for reads, update_database for writes.
Prerequisites
1uv pip install -U kern-ai sqlalchemy2# Plus your database driver:3uv pip install -U psycopg2-binary # PostgreSQL4uv pip install -U pymysql # MySQLExample
1from sqlalchemy import create_engine2from kern.agent import Agent3from kern.models.openai import OpenAIResponses4from kern.context.database import DatabaseContextProvider56# Two engines: one read-only, one writable7readonly_engine = create_engine("postgresql://reader:pass@localhost/mydb")8sql_engine = create_engine("postgresql://writer:pass@localhost/mydb")910db = DatabaseContextProvider(11 sql_engine=sql_engine,12 readonly_engine=readonly_engine,13 schema="public",14)1516agent = Agent(17 model=OpenAIResponses(id="gpt-5.4"),18 tools=db.get_tools(),19 instructions=db.instructions(),20)2122agent.print_response("How many orders were placed last month?")Warning
Both engines are required. The read sub-agent uses readonly_engine exclusively. Even if the model tries to run a write query, the database connection physically cannot execute it.
Provider Params
| Parameter | Type | Default | Description |
|---|---|---|---|
sql_engine | Engine | required | SQLAlchemy engine for writes. |
readonly_engine | Engine | required | SQLAlchemy engine for reads. Use a read replica or a user with SELECT-only permissions. |
schema | str | None | None | Scope queries to a specific schema. |
id | str | "database" | Provider ID. Tools become query_<id> and update_<id>. |
name | str | None | None | Display name. Defaults to id ("database"). |
read_instructions | str | None | None | Custom instructions for the read sub-agent. |
write_instructions | str | None | None | Custom instructions for the write sub-agent. |
mode | ContextMode | default | Tool exposure mode. See Architecture. |
model | Model | None | None | Model for the sub-agents. Defaults to Kern's default model. |
read | bool | True | Expose query_database tool. |
write | bool | True | Expose update_database tool. |
Tools Exposed
| Tool | Description |
|---|---|
query_database | Run SELECT queries, describe tables, explore schema. Uses readonly_engine. |
update_database | Run INSERT/UPDATE/DELETE queries. Uses sql_engine. |
Privilege Separation
The read and write sub-agents use separate database connections:
1query_database → readonly_engine → read replica / SELECT-only user2update_database → sql_engine → writable connectionThis is infrastructure-level protection. The read sub-agent's connection cannot execute writes regardless of what SQL the model generates.
Multiple Databases
Use different id values to expose multiple databases:
1orders_db = DatabaseContextProvider(2 id="orders",3 sql_engine=orders_write_engine,4 readonly_engine=orders_read_engine,5)67inventory_db = DatabaseContextProvider(8 id="inventory",9 sql_engine=inventory_write_engine,10 readonly_engine=inventory_read_engine,11)1213agent = Agent(14 model=...,15 tools=[*orders_db.get_tools(), *inventory_db.get_tools()],16)17# Agent sees: query_orders, update_orders, query_inventory, update_inventoryRead-only Mode
1db = DatabaseContextProvider(2 sql_engine=engine,3 readonly_engine=readonly_engine,4 write=False,5)6# Agent only sees query_databaseCookbook
database
Database Context Provider
Read/write with separate engines