How to govern LlamaIndex database agent tool calls

LlamaIndex agents connect to databases through tool specs or workflows. Here is how Deedglass intercepts each tool call, pauses sensitive writes for approval, and verifies committed rows.

The short answer

Connect your LlamaIndex FunctionAgent to Deedglass via the Model Context Protocol using BasicMCPClient and McpToolSpec. Deedglass serves standardized tools (postgres_query, postgres_execute, deedglass_check_approval) that enforce declarative policies ahead of execution3. Safe read operations run immediately, dangerous statements like DROP TABLE or TRUNCATE are blocked, and write queries wait for human confirmation in the Console or Slack3. When a write completes, Deedglass verifies the actual committed rows in PostgreSQL rather than trusting the text the agent generated.

Every MCP tool call goes through your rules first. Here a delete that doesn’t say which rows is stopped before it reaches the database. These are the rules deedglass init starts with; the call is made up.

Why LlamaIndex agents need pre-execution checks

LlamaIndex provides robust primitives for building context-augmented agents, query engines, and multi-step workflows. However, giving an autonomous agent access to write-capable database tools introduces distinct hazards:

  1. Unbounded update statements: An agent asked to update a specific record might omit a WHERE clause or generate a malformed filter, touching thousands of rows instead of one.
  2. Cascading schema mutations: Code generation models occasionally issue ALTER TABLE, DROP, or CREATE INDEX CONCURRENTLY inside active production transactions.
  3. No native per-tool gate: LlamaIndex’s built-in human-in-the-loop patterns rely on custom workflow event loops (InputRequiredEvent and HumanResponseEvent) where tool code calls ctx.wait_for_event1. The framework does not provide an external policy interceptor that gates individual tools across different client runtimes without modifying application code.
  4. Drift between intent and execution: Even when an agent issues a syntactically valid update statement, hidden triggers, foreign key constraints, or concurrent worker processes can alter additional rows without the model’s awareness.

Deedglass provides that boundary outside the agent’s code. The agent interacts with tools over MCP, while Deedglass evaluates each call against your security policy.

Connecting MCP tools in fifteen lines

LlamaIndex connects to MCP servers through llama-index-tools-mcp. The recipe below starts Deedglass’s local MCP gateway and provides its tools to a FunctionAgent3:

Code Program code, for developers. The text around it says what it does.

# Run from the folder where `npx deedglass init` was executed.
import asyncio
from llama_index.core.agent.workflow import FunctionAgent
from llama_index.llms.openai import OpenAI
from llama_index.tools.mcp import BasicMCPClient, McpToolSpec

async def main():
    client = BasicMCPClient("npx", args=["-y", "deedglass", "mcp", "serve"])
    tools = await McpToolSpec(client=client).to_tool_list_async()
    agent = FunctionAgent(
        name="orders_agent",
        description="Answers questions and updates order records.",
        llm=OpenAI(model="gpt-4o"),
        tools=tools,
    )
    result = await agent.run("How many rows are in public.orders?")
    print(result)

asyncio.run(main())

Install the dependencies:

Code Commands typed in a terminal. The text around it says what happens.

pip install llama-index-core==0.14.25 llama-index-tools-mcp==0.6.0 llama-index-llms-openai==0.8.3
python agent.py

Deedglass automatically translates tool names into identifiers accepted by language model APIs: postgres_query, postgres_execute, and deedglass_check_approval. Internal policies and ledger records maintain the dotted standard, such as postgres.query and postgres.execute.

Declaring policy rules for SQL tools

Policy rules live in your local .deedglass/policies.yaml file. The rule below allows read operations, requires human approval for single-row updates, and blocks bulk mutations:

Code A settings file: the rules a tool reads before it acts.

deedglass: policy/v1
name: orders-governance
defaults:
  decision: deny
  reason: "No rule permits this database operation."

rules:
  # Reads proceed immediately
  - id: allow-select-orders
    match: { tool: "postgres.query" }
    when: 'sql.kind == "select" && sql.tables == ["public.orders"]'
    decision: allow

  # Single-row updates require approval
  - id: approve-single-order-update
    match: { tool: "postgres.execute" }
    when: >-
      sql.kind == "update" && sql.tables == ["public.orders"]
      && !sql.unbounded_write && sql.has_where
    decision: require_approval
    reason: "Order updates require approval before writing to Postgres."
    approval: { approvers: ["role:support-lead"], required: 1, expires_in: 30m }

  # Destructive actions are denied
  - id: block-destructive-sql
    match: { tool: "postgres.execute" }
    when: 'sql.kind in ["drop", "truncate", "alter"]'
    decision: block
    reason: "DDL and destructive statements are forbidden."

When the LlamaIndex agent issues a SELECT query, Deedglass evaluates allow-select-orders, executes the query against Postgres, and returns the tabular result.

Human approvals in action

When the agent attempts an UPDATE statement, such as marking an order shipped, Deedglass intercepts the call before Postgres sees it:

  1. Deedglass evaluates approve-single-order-update and detects that decision: require_approval applies.
  2. The query is placed into a pending state in the Deedglass ledger.
  3. An approval notification is published to the Deedglass Console (and configured Slack channels).
  4. The tool returns a structured response to LlamaIndex:

Code Data in JSON, the format software uses to pass records and settings.

{
  "status": "pending_approval",
  "approval_id": "appr_01j9a8bc4d",
  "message": "Action paused. Order updates require approval before writing to Postgres.",
  "check_tool": "deedglass_check_approval"
}

The language model sees this message and can explain to the user: “I have requested approval to update order 42. Please approve it in the Console.”

Once the reviewer approves the action in Console › Approvals, the agent calls deedglass_check_approval with the approval_id, and Deedglass dispatches the transaction to Postgres.

Because the policy gate operates outside the Python process, you can change approval requirements, routing channels, and timeout durations without rewriting agent orchestration logic or redeploying client containers.

Verifying row diffs with Postgres CDC

Traditional agent logging captures only what the agent requested and what the database driver echoed back. If an update fired a legacy trigger or an unindexed cascade, the agent’s log says “Updated 1 row” while the database committed 300 rows.

Deedglass includes a change-data-capture reader built on Postgres logical decoding:

  • During query execution, Deedglass tags the transaction with the action ID.
  • The engine reads the write-ahead log (WAL) directly from Postgres.
  • It parses the committed row diffs and compares the count and primary keys against what the agent reported.
  • If the agent reported 1 row and Postgres committed 301, the action status is sealed as Doesn't match (Mismatch), and an alert is raised3.

Because the audit trail is sealed with Ed25519 signatures, the resulting record can be independently inspected offline with deedglass verify without requiring an active database or network connection3.

Each sealed record stores:

  • The agent identifier and session metadata.
  • The exact SQL AST evaluated by policy rules.
  • The authorizer identity and timestamp for gated actions.
  • The cryptographic hash of the committed WAL diff.
  • A cryptographic link to the prior record in the organization’s audit chain.

Testing without a model key

To verify your LlamaIndex pipeline without consuming API tokens, you can run the test script included in Deedglass’s framework test suite:

Code Commands typed in a terminal. The text around it says what happens.

npx -y deedglass init --yes
npx -y deedglass mcp serve

Run the local parity check:

Code Commands typed in a terminal. The text around it says what happens.

npx -y deedglass actions list

Every action issued by your agent is displayed with its policy decision, execution status, and verified row delta, giving you full operational visibility into your autonomous agents.

For related patterns across other frameworks, see OpenAI Agents SDK approvals, Mastra requireToolApproval, and Pydantic AI toolsets; the human-in-the-loop approval entry covers the idea. To see what the agents configured on your machine can change, paste the config into the check page or run npx deedglass scan (how the grade works); to try approval rules in your browser, open the playground.

Written with AI assistance and checked against our claims register.

The takeaway

LlamaIndex agents run database tools over MCP; Deedglass checks policies before execution and verifies the true rows Postgres changed.

Read nextPydantic AI tool approval: requires_approval and deferred tool results, tested Try it: install in 7 s

Related on this site

More posts

Sources

  1. 1LlamaIndex docs: Human-in-the-loop workflows · developers.llamaindex.ai · checked 30 October 2026
  2. 2LlamaIndex docs: Model Context Protocol tools · developers.llamaindex.ai · checked 30 October 2026
  3. 3Deedglass docs: LlamaIndex integration recipe · docs.deedglass.com · checked 30 October 2026

Published 30 October 2026, sources last checked 30 October 2026. If something here is out of date, write to hello@deedglass.com.

Try it on your own setup

npx deedglass scan

Grades only your own setup. Nothing is uploaded.

Pricing