A search engine whose results a model reads
Retrieval-augmented generation (RAG) is a search engine whose results are read by a model instead of a person. An agent is a model that is allowed to call tools. Every tool call is an action taken under someone's authority, and every retrieved chunk is a copy of something that had a permission on it.
That makes retrieval the place where AI meets data governance, and tools the place where AI meets authorization. The question to ask of any design is: where does information enter, what can the model see, what can it do, under whose authority, and how do we know it was right?
Permission-aware retrieval
Permission-aware retrieval, stage by stage
- 1.Connectors read the sources
- 2.Parse and OCR
- 3.Chunk by document structure
- 4.Attach metadataSource, ACL, label, residency, version, hash
- 5.Embed
- 6.Write to a hybrid index
- 7.Filter by the user's ACLs
- 8.Fuse keyword and vector results
- 9.Rerank
- 10.Re-check the top results at source
- 11.Build the context, with provenance
- 12.Answer, with citations
Every chunk should carry its metadata from the moment it is cut: the source, the ACL, the sensitivity label, the residency, the version and a content hash. Each later stage needs one of them. The ACL is for filtering, the label for the processing decision, residency for routing, the version and hash for knowing when it's stale, and the source for the citation.
Authorize before ranking, or verify after it
Order matters. If unauthorized items are ranked alongside authorized ones, they leak through the ranking itself: through result counts, through scores, through a summary that blends them. So either filter by permission before ranking, or verify after ranking and drop what fails, and ideally both.
There are four ways to bind permissions to retrieval, and they trade speed against exactness:
| Pattern | Strength | Weakness |
|---|---|---|
| Early binding: ACLs stored in the index | Fast | Stale by the length of the ACL sync; group explosion |
| Late binding: verify each result at the source | Exact | Latency, and the source's rate limits |
| Partitioned indexes, one per class or tenant | Isolation | Operational overhead |
| Delegated retrieval: the source searches as the user | Inherits the source's authorization exactly | Little control over ranking |
For regulated data, combine them: filter early using the ACLs in the index, verify the top results late at the source, and propagate deletions and ACL changes by event, under a freshness SLO. The worked example shows what late verification catches: a user removed from a Confluence space at 10:00 asks a question at 10:20, the hourly ACL sync hasn't run, the index still says yes, and the check at the source says no.
Storage classification against exposure classification
A common claim is that an index inherits the highest classification of its sources "unless it is partitioned or ACL-trimmed". That's half right. Trimming changes what a user sees. The index store still holds every chunk, and so do its backups, its logs, its administrators' view, its embeddings and its caches.
So keep two classifications apart:
- Storage classification is always the maximum of the inputs. It governs where the index may live, who may administer it and how it is backed up.
- Exposure classification is per request, after trimming. It governs what an answer may contain.
Partitioning reduces both. Trimming reduces only exposure. The Microsoft 365 two-decision model is consistent with this: Decision 1 is exposure; Decision 2 is permission to process. And an answer built from several chunks carries the highest classification among the chunks it cites.
Tools and MCP
The Model Context Protocol is the common way to give a model tools. Its 2026-07-28 revision changed the protocol's shape enough that designs written against the 2025 versions need revisiting.
- No more protocol sessions. The
initializehandshake and theMcp-Session-Idheader are gone. Every request carries its protocol version and the client's capabilities in_meta. - Servers must implement
server/discover,[1] which advertises versions, capabilities and identity. Clients may call it first, or use it as a compatibility probe. - Cross-call state uses server-minted handles, passed as ordinary tool arguments.
- A broken response stream loses the in-flight request. SSE resumability was removed, and the client must re-issue the request as a new one with a new ID.
- List results carry
ttlMsandcacheScope, a freshness hint and a flag saying whether shared intermediaries may cache them. - Clients must key stored credentials by issuer,[1] must not reuse them with a different authorization server, and must validate the
issparameter in authorization responses when it is present (RFC 9207). - Tasks moved to an official extension. Roots, Sampling and Logging are deprecated, and so is Dynamic Client Registration, in favour of Client ID Metadata Documents. Deprecations carry a minimum twelve-month window.
What that means for a design
"Stateless MCP" describes the transport, not the system. The protocol is stateless; the application isn't. State moves into handles and into your application, which has consequences:
- Every handle needs an ownership check on every call. With no session to hang authorization on, a handle from one user must not work for another.
- Side-effecting tools need idempotency keys. A broken stream means the client re-issues the request, so a tool that creates a ticket or makes a payment will be called twice unless it can recognise the repeat.
- A
publiccacheScope on a user-specific tool list is an authorization leak through any shared cache in between. - Pin issuers, and bind every credential to the authorization server that issued it.
- MCP servers become ordinary stateless services that sit behind standard load balancers and WAFs. Estates that mix old and new servers need a fallback to the old handshake.
Identity from user, to agent, to tool
How identity should travel from a user, through an agent, to a tool
User
Delegates a task
Entra agent identity
Created from a blueprint
MCP server
Stateless; checks every handle
Downstream API
Authorizes for itself
The user delegates to the agent. The agent exchanges that token for one bound to the MCP server's audience. The MCP server makes its own authorization decision before it calls the API. Never pass the user's token through unchanged. Each hop exchanges the token it received for one issued to the next audience, and the downstream API makes its own decision.
An agent can act in one of three modes:
- As the user, through on-behalf-of, so it can do only what both the user and the agent's scopes allow. Right for assistive tasks.
- As itself, with its own agent identity. Right for autonomous jobs that no single user owns.
- As an agent user, where something needs a directory user or a mailbox.
Whichever mode, the controls are the same: one identity per agent, Conditional Access at the blueprint level, short-lived federated credentials, a named human sponsor, deprovisioning when the agent is retired, and audit records that can tell a human's action from an agent's. The Microsoft 365 page covers how Entra Agent ID implements this.
Evaluation
Treat the AI system like software, and evaluate it like software:
- Golden sets for correctness.
- Claim-to-source entailment for groundedness: does each claim follow from the source it cites?
- Recall@k and MRR for retrieval.
- Red-team suites built on OWASP and MITRE ATLAS.
- Time to first token, p95 latency and cost per task.
- Pinned versions: model, prompt, index and tool schema together, with regression evaluation on every change.
- Sampled, judged production traffic.
Every route through the model gateway is a separate system under test. Evaluation cost scales with routes multiplied by versions, which is what keeps route explosion in check.
Threats to agentic systems
OWASP published its Top 10 for Agentic Applications for 2026 on 9 December 2025:
| ID | Risk |
|---|---|
| ASI01 | Agent goal hijack |
| ASI02 | Tool misuse |
| ASI03 | Identity and privilege abuse |
| ASI04 | Supply chain |
| ASI05 | Unexpected code execution |
| ASI06 | Memory and context poisoning |
| ASI07 | Insecure inter-agent communication |
| ASI08 | Cascading failures |
| ASI09 | Human-agent trust exploitation |
| ASI10 | Rogue agents |
| Threat | Control |
|---|---|
| Indirect injection through documents, email or calendar | Treat content as data, separate privileges, require approval for side effects |
| Exfiltration | Egress allow-lists, no arbitrary fetches or image rendering, DLP on output |
| Unauthorized retrieval | Permission-aware retrieval, as above |
| Identity confusion | Distinct identities and audience-bound tokens |
| Supply chain | Pinned, signed models and MCP servers; review of tool descriptions |
How agents fail
Indirect injection (ASI01). Tool misuse (ASI02). Identity abuse (ASI03). Memory poisoning (ASI06). Loops that run up cost and calls (ASI08), which need circuit breakers and step limits. Duplicate side effects when a request is re-issued. Deleted documents that live on in the vectors.
Trade-offs
Workflow or agent. A deterministic workflow suits work whose steps you can list. An agent suits open-ended tool choice, and brings the ASI risks, more tokens and new kinds of failure. Use the least autonomy that meets the requirement.
One agent or several. More agents add more inter-agent trust edges (ASI07), not more intelligence.
Questions to ask in a review
What can this agent do that the user couldn't? Which tools are idempotent, and what is each one's key? Where is the ACL checked relative to ranking? Who approves irreversible actions, and what happens when nobody is there to approve? What happens to the index when a document is deleted at the source?