Erdmates Logo
Erdmates
Back to Blog
AIMCPSchema DesignPostgreSQL

Databases Read by AI Agents: Schema Design Principles for the MCP Era

AI agents are increasingly connecting directly to databases through MCP. This post covers how to design names, comments, and constraints so agents don't misinterpret your schema, and how to split permissions safely.

October 12, 20268 min read

AI Agents Have Started Reading Databases Directly

MCP (Model Context Protocol) is an open standard that aims to unify how AI tools connect to external data and systems. Anthropic released it on November 25, 2024, and on December 9, 2025 it was donated to the Agentic AI Foundation under the Linux Foundation. Once you attach an MCP server for databases, an AI agent can look up the list of tables and their columns and execute SQL directly.

This shifts the design perspective. Human developers can read the internal wiki or ask a colleague, but what an agent sees is mostly the database catalog: table names, column names and types, constraints, and comments. The schema itself has to serve as the documentation, or the agent may join the wrong tables or misread units.

This post covers five principles, good for humans but even more important for agents, using PostgreSQL as the reference.

1. Use Meaningful Names, Not Abbreviations

Agents interpret abbreviations like usr_amt_cd by guessing. Guesses can be wrong.

-- Names to avoid: abbreviations, no units, meaningless flags
CREATE TABLE ord (
  id     BIGINT PRIMARY KEY,
  usr    BIGINT,
  amt    NUMERIC,
  flg    CHAR(1),
  dt     TIMESTAMP
);

-- Recommended: meaning, units, and time zone show up in names and types
CREATE TABLE orders (
  id            BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  customer_id   BIGINT        NOT NULL,
  amount_krw    NUMERIC(12,0) NOT NULL,
  is_refunded   BOOLEAN       NOT NULL DEFAULT false,
  ordered_at    TIMESTAMPTZ   NOT NULL DEFAULT now()
);
  • Put units and currency in the name: amount_krw, duration_ms, weight_g
  • Prefix booleans with is_ or has_: is_refunded instead of flg
  • Use the same name for the same concept in every table: if one place uses user_id and another uses member_no, the agent can't tell whether they are the same thing
  • Use TIMESTAMPTZ for points in time: values without a time zone are open to different interpretations, by humans and agents alike

2. Record Meaning in the Catalog with COMMENT ON

PostgreSQL's COMMENT ON stores descriptions in the catalog (pg_description). Unlike code comments or a wiki, these descriptions travel with the database, so any tool that inspects the schema can read them through the same path.

COMMENT ON TABLE orders IS 'Customer order. Created when payment completes; the row is not deleted on cancellation (marked with is_refunded).';
COMMENT ON COLUMN orders.amount_krw IS 'Payment amount (KRW, VAT included). Amount after discounts are applied.';
COMMENT ON COLUMN orders.is_refunded IS 'Whether the order was fully refunded. For partial refunds, see the refunds table.';

You can query the stored descriptions like this:

SELECT a.attname                                  AS column_name,
       format_type(a.atttypid, a.atttypmod)       AS data_type,
       col_description(a.attrelid, a.attnum)      AS description
FROM pg_attribute a
WHERE a.attrelid = 'orders'::regclass
  AND a.attnum > 0
  AND NOT a.attisdropped;

What should you write?

  • The unit and scope of values (whether VAT is included, before or after discounts)
  • The meaning of status values and their transition rules
  • Whether soft deletion is used, and the conditions for a row that is "actually valid"
  • Caveats in relationships with other tables (e.g., partial refunds are in another table)

3. Express Rules as Constraints: Agents Can't See Application Code

If the rule "this column is one of pending, paid, or shipped" exists only in application code, it is a rule that doesn't exist as far as the agent is concerned. Declared as a constraint, it can be read from the catalog, and it becomes the last line of defense: the database rejects invalid values even when someone tries to write them.

CREATE TABLE customers (
  id     BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  email  TEXT NOT NULL UNIQUE
);

CREATE TABLE shipments (
  id           BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  order_id     BIGINT NOT NULL REFERENCES orders (id),
  status       TEXT   NOT NULL
               CHECK (status IN ('pending', 'paid', 'shipped', 'delivered')),
  shipped_at   TIMESTAMPTZ,
  CHECK (status <> 'shipped' OR shipped_at IS NOT NULL)
);
  • Declaring foreign keys explicitly lets the agent confirm join paths in the catalog instead of guessing them
  • CHECK exposes allowed values and rules between columns
  • NOT NULL and UNIQUE convey the facts "always present" and "only one"

4. Organize What the Agent Sees with Views

If you leave the agent to compute "monthly revenue" from the raw tables every time, whether refunds are included or how time zones are handled can differ from one question to the next. Fix the agreed-upon definition in a single view and attach a description, and the agent can just use that view.

CREATE VIEW monthly_revenue AS
SELECT date_trunc('month', ordered_at AT TIME ZONE 'Asia/Seoul') AS month_kst,
       sum(amount_krw)                                          AS revenue_krw,
       count(*)                                                 AS order_count
FROM orders
WHERE NOT is_refunded
GROUP BY 1;

COMMENT ON VIEW monthly_revenue IS 'Monthly revenue (KRW). Months in Korea Standard Time; fully refunded orders excluded.';

5. Least Privilege: GRANT Is the Boundary, the Rest Is a Safety Net

Create a separate role for the agent's account and grant it only read access to the schemas it needs.

CREATE ROLE ai_reader LOGIN;  -- Set the password and authentication method according to your production environment's policy

GRANT USAGE  ON SCHEMA analytics TO ai_reader;
GRANT SELECT ON ALL TABLES IN SCHEMA analytics TO ai_reader;
ALTER DEFAULT PRIVILEGES IN SCHEMA analytics GRANT SELECT ON TABLES TO ai_reader;

-- Defaults to prevent mistakes (not a security boundary)
ALTER ROLE ai_reader SET default_transaction_read_only = on;
ALTER ROLE ai_reader SET statement_timeout = '15s';

There is one caveat. default_transaction_read_only and statement_timeout are settings the user can change back within a session. They reduce the chance of accidentally sending a write query or of a heavy query running for a long time, but they don't prevent either. The real boundary is the privileges granted with GRANT.

  • It is safer to leave personal data columns out of the views in the agent's schema entirely
  • If you need to scope access row by row, use ALTER TABLE ... ENABLE ROW LEVEL SECURITY with policies (CREATE POLICY)
  • Connecting to a read replica instead of the production primary reduces the impact of heavy analytical queries on your service

Designing with Erdmates

When you write descriptions for tables and columns in Erdmates, they are included as COMMENT ON TABLE and COMMENT ON COLUMN statements when you export PostgreSQL DDL (for MySQL, a table COMMENT). Conversely, when you import SQL from an existing database, Erdmates reads the COMMENT ON statements and restores them as descriptions in the ERD. If you refine names and descriptions while checking foreign key relationships as lines in the ERD, humans and agents end up looking at the same documentation.

Conclusion

Schema design in an era when agents work with databases directly is not a new technology; it is following old principles more strictly. Names that reveal meaning, descriptions that stay in the catalog, rules declared as constraints, views that hold agreed-upon definitions, and least privilege. A schema with these five makes agents less likely to get things wrong, and even when they do, the database stops them.

Start with Erdmates Today

Start designing databases with our AI-powered ERD editor. Free to use.

Try Free DemoStart for Free

Related Articles

bigint, UUID v4, or UUID v7? How to Choose a Primary Key (with PostgreSQL 18's uuidv7())

Compare bigint, UUID v4, and UUID v7 primary keys, see what PostgreSQL 18's built-in uuidv7() changes, and learn which key to pick for each situation.

PostgreSQL 19 Preview: Changes That Affect Schema Design and Operations (as of Beta 4)

Ahead of its official release, this post covers the PostgreSQL 19 changes that directly affect table design, migrations, and operations, based on the official release notes (Beta 4). It also looks at features reverted during beta and behavior changes to check before upgrading.

Designing Vector Tables for RAG with pgvector: Dimensions, Indexes, and Filtering

A guide to table structure, per-type dimension limits, HNSW indexes, and metadata filtering design when storing document embeddings with pgvector in PostgreSQL, based on pgvector 0.8.

Erdmates Logo
Erdmates

Design databases with natural language and collaborate in real-time with your team using our AI-powered ERD editor.

Service

  • Features
  • Pricing
  • Demo
  • SQL to ERD converter

Resources

  • Blog
  • Help
  • Contact Us

Legal

  • Terms of Service
  • Privacy Policy
  • Third-Party Provision
Company: Produx|Representative: 최정회
Address: 강원특별자치도 원주시 솔우물2길 4-1 (무실동)
Email: master@erdmates.com
Privacy Officer: 최정회|Hosting Provider: Amazon Web Services

© 2026 Produx. All rights reserved.