
Once an autonomous agent moves past answering questions and starts running an operational workflow — tracking IT assets, managing a CRM pipeline, logging sensor readings — it needs somewhere to put state that survives between turns. The Model Context Protocol (MCP) makes the agent’s reasoning portable across clients. It says nothing about where the agent’s data lives.
Engineering teams wiring up an MCP server for an agent backend converge on one of three storage patterns: a local SQLite file, a direct PostgreSQL connection, or a remote API-driven service exposing dynamic, typed schemas. Each shapes what the agent can safely do, how the resulting system behaves once a second agent or a human teammate needs to see the same data, and how much operational surface a solo engineering team has to maintain.
Pattern 1: Local SQLite files
A single .db file on disk is the fastest way to get an MCP server storing something. No server process, no network round-trip, no credentials to provision — the agent (or the MCP server acting on its behalf) opens a file handle and starts writing rows.
This works well for a single agent maintaining private working memory on one machine: a local task queue, a scratch cache of API responses, a personal notes store. It breaks down the moment more than one consumer needs the data:
- No team or multi-agent sharing. The file lives on one filesystem. A second agent instance, a teammate’s laptop, or a scheduled job running on different infrastructure has no path to the same state without a separate sync mechanism.
- No native audit history. SQLite stores current values. Knowing who changed a row and what it looked like a week ago means the application layer hand-rolling its own change-log table and populating it on every write.
- Manual concurrency handling. SQLite serializes writers at the file level. An agent fleet writing concurrently needs its own retry and locking logic on top, or writes start failing under contention.
- No built-in network access control. Reaching the file from anywhere other than local disk means standing up a sync layer or a wrapper API — at which point the team is building the access-control and multi-tenancy story the other two patterns already provide.
SQLite remains the right call for strictly single-agent, single-machine, ephemeral state. It is not a backend for an agent whose output other people or other agents need to see.
Pattern 2: Direct PostgreSQL connections
Handing an agent a PostgreSQL connection string solves the sharing problem — any client with network access and credentials reaches the same data — but it reintroduces the constraints relational databases were built around: schema as a deployment artifact, and credentials sized for a database administrator handed to a single tool call.
- Rigid DDL migrations. Adding a field the agent didn’t anticipate at setup time means writing and running a migration (
ALTER TABLE ... ADD COLUMN), the same release-cycle friction that makes fixed SQL schemas a poor fit for agent-driven data modeling in general. - Connection pooling overhead. Agent processes are frequently short-lived and bursty. Each one opening and closing raw database connections works against how Postgres connection pooling is meant to be used, and pushes the team toward operating a pooler (PgBouncer or equivalent) as another piece of standing infrastructure.
- Administrative credentials in the agent’s hands. To create tables, alter columns, or manage its own schema, the agent needs privileges well beyond row-level read/write — the same excessive-privilege exposure that makes direct DDL access an anti-pattern for autonomous execution. A prompt injection or a hallucinated query now carries the blast radius of a database administrator, not a scoped API client.
- No row-level access control out of the box. Postgres roles and grants exist, but scoping them per agent, per tenant, or per record requires the team to design and maintain that policy layer itself — it isn’t a property of “have a Postgres connection.”
Direct PostgreSQL access gives an agent real relational guarantees, at the cost of taking on schema deployment, connection management, and privilege design as ongoing engineering work.
Pattern 3: Remote dynamic schemas over MCP
The third pattern moves the agent off both a private file and a raw database socket, onto a remote MCP server backed by dynamic typed schemas: attributes, templates, and entities that agents declare and evolve through API calls alone.
- API-driven schema changes, no migrations. Adding a field is a tool call that registers a new typed attribute and makes it immediately readable and writable — no release cycle, no downtime.
- Granular OAuth 2.1 RBAC. Agents authenticate over OAuth 2.1 with PKCE, scoped strictly to the specific project a credential grants, so a compromised or misdirected agent session cannot reach data outside its grant.
- Built-in immutable audit trails. Every attribute mutation is logged with author attribution — whether a human user or a specific MCP-connected agent made the change — without the team writing a single trigger or shadow table.
- Native time-series metrics. Attributes declared as metrics stream straight into a purpose-built telemetry path, with retention and aggregation handled natively by the platform.
An agent connected this way calls a standard MCP tool or REST endpoint; the platform resolves the schema change, enforces the caller’s scope, and records the change to the audit ledger, all in the same request.
# Create an entity via a typed template, scoped to one project and one credential grant
curl -X POST "https://api.omnismith.io/v1/entities/template/it_asset" \
-H "Authorization: Bearer omni_live_secret_key_..." \
-H "X-Omnismith-Project-Id: $PROJECT_ID" \
-H "Content-Type: application/json" \
-d '{
"attributes": {
"asset_tag": "LAPTOP-0142",
"assigned_user": "[email protected]",
"warranty_expires": "2027-03-01",
"status": "In Service"
}
}'
# Add a temperature reading to a metric attribute — no schema change, no migration
curl -X POST "https://api.omnismith.io/v1/entities/$ENTITY_ID/metrics" \
-H "Authorization: Bearer omni_live_secret_key_..." \
-H "X-Omnismith-Project-Id: $PROJECT_ID" \
-H "Content-Type: application/json" \
-d '{
"metric_values": [
{ "attribute_slug": "cargo_temp", "value": "-18.4" }
]
}'
Both calls carry the same two headers regardless of which template or attribute they target: a bearer token scoped to the calling agent, and a project identifier naming the tenant the call acts on. Neither exposes a table name, a column type, or an administrative credential — the agent operates entirely through the typed attribute and template surface.
Structural comparison
| Capability | Local SQLite File | Direct PostgreSQL Connection | Remote Dynamic Schema (MCP) |
|---|---|---|---|
| Setup Time | Zero — a file on disk | Provision a database, pooler, and roles | Zero — connect and authorize |
| Multi-Agent / Team Sharing | None (single filesystem) | Yes, via network access | Yes, natively |
| Schema Change Latency | Instant, but unstructured | Migration + deploy cycle | Sub-second API mutation |
| Agent Credential Scope | Filesystem permissions only | Often administrative DB rights | Project-scoped OAuth 2.1 grant |
| Audit Trail | None built in | Requires custom triggers | Immutable, author-attributed by default |
| Time-Series Telemetry | Not supported natively | Requires a dedicated extension or table design | Native metric attribute type |
| Concurrent Writers | Serialized at the file level | Handled by the database, needs a pooler | Handled by the platform |
| Operational Visibility for Humans | None without custom tooling | Requires a hand-built admin UI | Auto-generated table and detail views |
Choosing a pattern for the workload in front of you
None of these three patterns is wrong in isolation — each is scoped correctly for a different blast radius. A single agent maintaining private scratch state on one machine has no reason to reach for a networked service; SQLite is the right tool. A team that already operates PostgreSQL infrastructure and wants an agent to participate as one more carefully scoped application client, with its own least-privilege role and no DDL rights, can make that work.
Where both patterns run into trouble is the case this series keeps returning to: an agent tasked with standing up a new operational system on demand — an IT asset tracker, a CRM pipeline, a fleet of sensors — for a team that expects the result to be immediately shared, auditable, and visible without separate frontend work. That combination of requirements is what a remote, dynamic-schema MCP server is built to satisfy: the agent gets a scoped credential and a schema it can evolve through API calls, and the team gets multi-tenant access control, an audit ledger, and a working interface without writing any of the three by hand.
This comparison builds on the schema-flexibility case made in Why Fixed SQL Schemas Break Autonomous Agents (and Why Runtime Schemas Win), and pairs with the mechanics of referencing attributes by project-unique slugs once an agent starts writing structured records against those schemas at scale.
To connect an agent to a remote dynamic-schema backend directly, see the Model Context Protocol guide.