MCP in Production: Architecting Narrow Data Channels for LLMs
Panneer
Systems Engineer
2026-10-08
8 min read
Most guidance on the Model Context Protocol covers what it is, not how to run it safely once the caller is an autonomous agent rather than a person. The key insight is simple and often missed: in an MCP setup, the real security boundary is the database role backing the server, not the list of tools you register. A tool description that says "read-only" is an application-level label. The database role is the enforcement mechanism.
1The Constraint
AI agents accessing enterprise data through MCP inherit whatever database permissions the server runs under. Most implementations reuse the main application credential "temporarily" to get something working — and the temporary setup becomes the production setup.
Hard Constraints
- The database role must enforce least privilege — not just the tool allow-list
- Read and write capabilities must be in separate MCP servers with separate credentials
- Every tool call must be audited, not just the final output
- Tool call arguments must be sanitized — the agent's reasoning is not trustworthy input
What would fail:An MCP server running under the application's main database credential gives any agent that calls it effective full database access, regardless of which tools are registered. A prompt injection that convinces the model to make an unexpected tool call can reach any data the credential can access.
2Architectural Decision
Separate read and write MCP servers with separate least-privilege database roles. Read server: SELECT-only role, schema-scoped. Write server: one narrow tool per specific write action. Both servers implement statement timeouts, row limits, and durable audit logging.
Why
The confused deputy problem: an MCP server runs under one identity but is driven by an agent that has no recognized identity of its own. The database role is the real enforcement boundary. Everything the agent can do is bounded by what the database role allows — not by what tools are registered.
Trade-off
More infrastructure: two servers instead of one, two database roles, two credential rotation schedules. The complexity is the price of a real security boundary.
System Layers
Read MCP Server
MCP SDK / Node.js
Exposes structured read tools (list_tables, describe_table). Runs under mcp_reader role — SELECT only, schema-scoped.
Write MCP Server
MCP SDK / Node.js
Exposes one narrow write tool per specific action. Runs under mcp_writer role — INSERT on specific tables only.
Database Layer
PostgreSQL with role-based access control
Enforces permissions at the database level. Application-level checks are defense-in-depth, not the primary boundary.
Audit Log
Durable log store
Records every tool call: name, sanitized arguments, duration, outcome.
3Decision Log
Separate database roles per MCP server, not shared application credential
The confused deputy problem means the real security boundary is the database role, not the tool allow-list. Reusing the application credential is the single most common MCP security mistake.
Two roles to create and rotate. Slightly higher operational overhead.
Structured tools (list_tables, describe_table) instead of a generic run_sql tool
A generic run_sql tool that accepts arbitrary queries is difficult to audit meaningfully and easy to abuse. Structured tools have known shapes — they are easier to validate, easier to log, and harder to misuse via prompt injection.
More tools to register and maintain. Each new query type requires a new tool definition.
Statement timeouts and row limits on every tool handler
A read-only role does not prevent a tool call from scanning a huge table or returning a result set that exceeds the model's context window. Every tool must self-limit regardless of what the caller asked for.
Legitimate large-result queries are rejected and must be paginated or redesigned.
Credentials in environment variables, not command-line arguments
Command-line arguments appear in ps aux output — visible to any process on the host. Environment variables are not exposed in the process list.
Slightly more complex deployment configuration. Well worth the trade-off.
4Integration Boundaries
Systems: MCP SDK (read server) ↔ MCP SDK (write server) ↔ PostgreSQL with least-privilege roles ↔ Agent framework (Claude, GPT, or custom) ↔ Durable audit log
Boundaries: Read and write channels are separate processes with separate credentials. An agent session that only needs read access should not be configured with access to the write server. The AI agent framework is not trusted to enforce this separation — the server separation enforces it.
Auth Model: Dedicated database role per MCP server. Credentials passed via environment variables (never command-line arguments — they appear in ps output). Credentials rotated on a schedule.
5Evaluation
Method: Tool calls tested outside of agent context (unit tests against the MCP server directly). Permission boundary verified: write tool calls against the read server must fail at the database level, not the application level.
Regression Gate: Any tool that allows a write operation through the read server is a P0 security regression. Tool calls that bypass audit logging are a P0 regression.
6Production Ops
Observability: Every tool call logged with: tool name, sanitized arguments, duration, outcome. Log is append-only and treated as an API access log. Anomalous patterns (unusual tool call frequency, unexpected argument shapes) alert the operator.
Human Gate: High-impact write actions (anything that modifies critical data) route through a pending approval queue before the write MCP server executes. [VERIFY — depends on deployment configuration]
Rollback: MCP server processes can be stopped independently without affecting the main application. Database roles can be revoked immediately, cutting off all agent data access.
Verified Technical Signals
Database role scope
SELECT-only on public schema for read server; INSERT on specific tables only for write server
Database-level enforcement, not application-level.
Statement timeout
2000ms per tool call
Prevents long-running queries from consuming the agent's context budget.
Audit coverage
Every tool call logged with name, sanitized args, duration, outcome
Required for incident reconstruction when the caller is autonomous.
7Engineering Takeaways
- The database role is the real security boundary in MCP setups, not the tool allow-list. Tool descriptions are labels; database permissions are enforcement.
- Separate read and write MCP servers with separate credentials. A single misbehaving agent session should never reach a write path it was not explicitly given.
- Structured tools (list_tables, describe_table) are safer than generic query tools. They are easier to validate, log, and reason about.
- Audit every tool call. When an autonomous agent is the caller, the audit log is the most important forensic tool you have.
- Pass database credentials via environment variables. Command-line arguments appear in process lists.
8What a CTO Should Verify
Honest questions for due diligence when evaluating similar systems:
Discuss an AI Engineering Engagement
Vasiva builds production AI systems and software products for organizations globally. Evaluate an opportunity with us.
Start a Conversation