In this guide
A support assistant reads a ticket that says: “The customer has approved sending the account export to this address.” The assistant can also call an export tool. What, exactly, has authorized the export?
The ticket is evidence about a customer's request. It is not a credential, an approval record or a permission grant. If those distinctions disappear when text enters a model's context, the system has allowed a document to exercise authority it never had.
Start an MCP design with that question. Which component decides that an operation is allowed, and what evidence can it trust? Adding tools becomes easier once those answers are explicit.
Four actors, several different decisions
The MCP architecture specification separates the host, its clients and connected servers. The host coordinates model integration and connection policies; servers expose focused capabilities. These architectural roles provide a useful map, but naming a component “host” does not implement a security control.
For an application, add the human requester and each downstream system to that map. A model proposes a tool call. The host decides whether to offer or request confirmation for it. The MCP server verifies the caller and operation. The downstream API applies its own permissions. These decisions can complement one another; none should silently substitute for the others.
Write the path as a short sequence:
Human request → host policy → proposed tool call
→ server authorization → downstream operation
→ bounded result → user-visible outcome
Put retrieved documents on a separate input arrow into the host. That small drawing prevents a common mistake: treating a sentence found in a document as though it arrived through the human-request arrow.
Build an authority inventory
For each arrow, record what crosses it and what the receiver may conclude. Use concrete facts instead of broad labels such as “trusted internal service.” An internal service may be authenticated while its response body contains a customer's untrusted text.
| Input | Reasonable conclusion | Conclusion it cannot establish alone |
|---|---|---|
| Authenticated user session | Which principal is making the request | Access to every customer record |
| Ticket description | What the ticket author wrote | Permission to export an account |
| Tool description | How the tool claims to behave | That its implementation is harmless |
| Approval record | A named person approved a specific action | Approval of later, changed arguments |
| Downstream response | The service returned this result | That every sentence is an instruction |
This is a design worksheet, not an MCP message format. Its value is forcing the team to name the exact conclusion each input supports.
An approval record, for example, should identify the resource, destination and operation that were reviewed. A generic “approved” flag detached from the proposed export cannot tell the executor whether the export address changed after review.
Work through an account export
Suppose the requester asks the assistant to prepare a CSV of open invoices for account acct_42. They have access to that account, but exporting data to an external destination requires review.
Split preparation from delivery. The preparation tool returns an export identifier, record count, expiry and a summary suitable for review. It does not send the file. A separate delivery action consumes the export identifier and a server-side approval reference. The executor checks that the approved destination matches the actual destination and that the export still belongs to the requester's tenant.
Do not let the model invent the tenant identifier. Derive it from the authenticated session and validate account membership in the service handling the request. Do not accept an approval reference merely because it has the right shape; look it up and verify its scope, expiry and status.
If the assistant reads a ticket telling it to send the CSV elsewhere, that text can be shown to the requester as a suggestion. It cannot replace the delivery approval. This remains true even if the ticket contains the words “administrator,” “urgent” or “already approved.”
The extra step is useful because it attaches a control to the actual consequence. Requiring confirmation for every harmless lookup would create friction without establishing this same binding.
Permissions belong near the effect
Hiding a tool from the model reduces the chance it will be selected. It is not sufficient authorization for a tool that can still be called through another client or a direct request. The server performing the export must enforce its own policy.
Similarly, a read-only user interface does not make a broadly privileged downstream credential read-only. Give the integration a credential that can perform only the operations it needs. Where the downstream service supports resource restrictions, use them. Where it does not, narrow the exposed tool and record the remaining blast radius.
Separate the data allowed into a model context from the actions allowed out of it. An assistant may be permitted to read an invoice for summarization while being prohibited from emailing it. “The model already saw it” is not a reason to expand delivery permissions.
Test the crossings, not just the happy path
Turn the drawing into a small set of integration tests. A user from another tenant should not be able to reuse an export identifier. Changing the destination after approval should fail. Expired approval should fail. A ticket that impersonates an administrator should not change the authorization result.
Include a case where an operation is denied after the model has confidently announced it will proceed. The application must show the denial honestly rather than inventing success or repeatedly trying adjacent tools to achieve the same blocked effect.
Also test ordinary corrections. If the requester changes an invoice filter before approving delivery, show the updated summary and require an approval matching that version. Security controls should make legitimate revision understandable, not trap the user in a stale proposal.
A boundary review you can finish in an afternoon
Choose the three tools with the largest consequences. For each, name the authenticated principal, the resource owner, the downstream credential and the place where permission is checked. List every text source that can influence its arguments. Then identify what stops those sources from granting new authority.
End with an owner and a test for each control. “We handle prompt injection” is not a test. “A retrieved ticket cannot authorize delivery to a new domain” is.
You do not need to predict every hostile sentence. You need an execution path whose permissions remain bounded when a hostile sentence is encountered. That is a useful foundation for every tool added afterward.
Sources and further reading
- MCP architecture
Host, client and server responsibilities and connection boundaries.