Governed MCP vs Raw Database MCP: What Do You Lose When an Agent Hits the Database Directly?
Identity, masking, write review and audit are the four things a raw database MCP server skips
A raw database MCP server skips four controls that a governed one enforces: per-user identity, column masking, write review and audit. Bytebase makes this argument directly, saying a raw MCP server skips identity, masking, write review and audit. We agree with the diagnosis. The agent connects as one shared service account, sees every column the account can see, can run whatever statement the model produces, and leaves no record that ties an action to a person or a prompt. This post explains each gap and gives a checklist for closing it.
Key Takeaways
- •A raw database MCP server authenticates the agent, not the human behind it, so every query looks like the same service account in the database logs.
- •Masking has to happen before results reach the model, because anything returned in a tool result can end up in the model's context and in downstream tool calls.
- •The MCP specification says there SHOULD always be a human in the loop who can deny tool invocations, which a raw server leaves entirely to the client.
- •An audit trail is only useful if it records who asked, what the agent ran, what was approved and what changed. Native database logs record only the last of these.
- •Governed does not mean read-only forever. It means every write passes a reviewable gate with an owner, a scope and a receipt.
What a raw database MCP server actually is
A raw database MCP server is a thin wrapper. It exposes tools such as run_query or list_tables, takes a connection string from an environment variable, and forwards whatever SQL the model writes. That is useful for a demo and fast for a developer on a laptop. It is also the shortest possible path from a language model to production tables. Nothing sits between the prompt and the engine except the privileges of the account in the connection string.
The wrapper does exactly what it says, and that is the problem. It has no concept of the person who typed the question, the sensitivity of the columns in the result, or the difference between a SELECT and a DROP. Those distinctions live in policy, and policy lives outside the wrapper. When the wrapper is the only layer, the policy is whatever the service account happens to be allowed to do, which is usually broader than anyone intended.
Teams reach for this pattern because it works on the first try. A developer points Claude Code or Cursor at a warehouse, asks "what changed in the orders schema since last deploy?", and gets an answer in seconds. The risk does not show up in that first session. It shows up when the same configuration is copied to a shared environment, where the account has write privileges and the questions come from people nobody reviewed.
Gap one: identity gets flattened into a service account
The first thing a raw server loses is who is asking. The MCP authorization specification defines an OAuth-based flow for HTTP transports so a client can act on behalf of a user. A raw server that reads a static connection string ignores that flow. Every request reaches the database as the same principal, whether it came from a staff engineer, an intern or an automated job.
This breaks least-privilege in a quiet way. Row-level and column-level rules in the warehouse are written per role. If the agent always connects as one role, the role must be wide enough for the most privileged person who might use it. Everyone else inherits that width. A governed server maps the calling user to their own role, so the agent can see exactly what that person could see and nothing more.
It also breaks accountability. When a query runs at 02:14 and drops a table, the database log says the service account did it. Finding the person, the prompt and the session means stitching together logs from the client, the model provider and the server, if they exist at all. Identity propagation turns that investigation into a single lookup.
Gap two: results reach the model unmasked
The second loss is masking. A tool result is not private to the tool. It is returned to the model, which may quote it, summarize it, pass it to another tool or write it into a file. If a query returns email addresses, national IDs or card fragments, those values are now in the context window. Asking the model to "ignore PII" is an instruction, not a control.
Masking has to run in the server, on the result set, before it leaves. That means classifying columns, applying a rule per role (redact, hash, truncate or allow), and logging that the rule fired. Warehouses offer native tools for this, such as dynamic masking policies, but they only help if the agent connects as a role those policies apply to. A shared service account with broad access often bypasses them entirely.
The question we hear most is "who has access to PII columns in analytics?" It is a good question to ask before connecting an agent, not after. Our Governance Agent detects PII columns and generates the RBAC policy for them, so the mask exists before the first agent query runs, not in a cleanup ticket afterward.
Gap three: writes skip review
The third loss is write review. The MCP tools specification states that for trust and safety there SHOULD always be a human in the loop with the ability to deny tool invocations. That is a recommendation to client builders. A raw server does not enforce it, and many clients let users approve once and then auto-run. The server is the only place a write gate can be guaranteed, because it is the last hop before the database.
A governed server classifies each statement. Reads go through. Writes are parsed, checked against an allow-list of operations and objects, and routed to an approval step with a named reviewer. The reviewer sees the exact statement, the estimated rows affected and the blast radius, for example which downstream models depend on the column. Only then does it execute, ideally against a clone first.
This is the same problem we covered in safe write access through an MCP server. The short version is that an agent that can write without a gate is one bad inference away from an incident. The gate does not slow the common case. Most agent traffic is diagnosis, and diagnosis is read-only.
Gap four: audit stops at the database log
The fourth loss is audit. Warehouses keep good records of what ran. Snowflake, for instance, retains ACCESS_HISTORY for 365 days, recording which columns each query read. That is valuable, but it answers a narrower question than an auditor asks. It tells you a query touched a column. It does not tell you which human prompted the agent, what the model was told, who approved the write or why.
A governed MCP layer writes its own record at the point of decision: caller identity, tool name, the statement, the masking rules applied, the approval and the outcome. Joined to the warehouse history by query ID, it gives a chain from request to row. For SOC 2, GDPR or HIPAA evidence, that chain is the difference between a screenshot and a report.
Tamper-evidence matters here too. An audit log the agent's own credentials can edit is not evidence. Append-only storage, hash chaining or an external sink keeps the record trustworthy even when the system it describes is compromised.
A checklist for telling which one you are running
You can test any MCP database server in an afternoon. Run the same question as two different users and check whether the database sees two principals. Query a table with a known sensitive column and check whether the value reaches the model. Ask the agent to update one row and check whether anything stops it. Then try to reconstruct the session from logs alone. Each test maps to one of the four gaps.
- •Identity: does the database log show the human's role, or only a shared service account?
- •Masking: does a PII column come back redacted for a role that should not see it?
- •Write review: does an UPDATE or DROP pause for a named approver before it runs?
- •Audit: can you find who asked, what ran, who approved and what changed from one record?
- •Scope: can you limit the agent to specific schemas, tables and operations without changing the database role?
If you answer no to two or more, you are running a raw server, whatever the documentation calls it. That is not a reason to stop using agents on data. It is a reason to put the control layer between them and the engine before the pilot becomes a dependency.
How Data Workers handles it
Every Data Workers agent is an MCP server, and the controls above are enforced at the framework level rather than per tool. The open-source edition is read-only by default and runs locally, so the first session cannot write anything. Pro adds writes behind approval workflows and audit trails. Enterprise adds SSO/SAML, multi-tenant isolation and VPC or on-prem deployment, so data never leaves your infrastructure.
In practice that means an engineer in Claude Code or Cursor asks "what's the blast radius if I drop this column?" and gets an answer scoped to their access. If the follow-up is a migration, it becomes a reviewed change with an owner and a receipt. The Incidents, Schema and Pipeline agents share that context, so a fix proposed by one is checked against the policy known to the others.
We would rather you adopt the pattern than our product. If you already run a gateway that enforces identity, masking, review and audit, keep it. The point is that the four controls exist somewhere between the model and the table.
Frequently Asked Questions
Is a read-only database role enough for a raw MCP server?
A read-only role removes the destructive-write risk, which is a large improvement, but it leaves three gaps open. The agent still connects as one shared principal, so identity and per-user rules are flattened. It can still read every column the role can read, so sensitive values reach the model unmasked. And the audit trail still lacks the human and the prompt. Read-only is a good floor, not a governance layer.
Does a governed MCP server add noticeable latency?
Identity lookup, statement classification and masking are in-process operations that add little next to a warehouse query. Approval steps do add wall-clock time, but only for writes, which are a small share of agent traffic. Diagnosis questions like "why did row counts drop 40% overnight?" are reads and do not wait on a human.
Can I add governance to an existing MCP server instead of replacing it?
Yes. A governing proxy can sit in front of an existing server, authenticate the caller, rewrite or reject statements, mask results and log decisions. The trade-off is that two components now have to agree on policy. Many teams find it simpler to run one governed server that owns identity, masking, review and audit end to end.