AFP engineering series · Chapter 15 of 25
Protect an agent from overprivileged MCP integrations, misleading tool descriptions, token misuse, and unsafe outbound requests.
Adding a tool adds a trust relationship
An MCP server can expose useful capabilities to an assistant, but discovery is not approval. A server's tool description explains what it claims to do. It does not prove that the implementation is safe, that the user consented to every capability, or that the server should receive all context available to the agent.
Maintain an approved integration inventory with owner, server identity, tool names, schemas, credential scope, data classes, and expected destinations. Treat changes to descriptions and schemas as reviewable changes because they can alter model behavior or the shape of requests. A familiar display name is not a stable identity.
Protect both protocol authorization and business authorization
The MCP authorization specification defines protocol-level requirements, while its security guidance discusses threats such as confused-deputy behavior and token handling. Follow the applicable version for the transport you deploy. Then add the resource-specific checks your business requires.
An access token authorizing an integration does not necessarily authorize every order, document, or recipient. The downstream service must still evaluate the acting subject and resource. Keep token audience and scope aligned with the intended server, and never forward a token to another destination simply because a tool result requests it.
Minimize the context sent to a tool
A search tool usually needs a query, not the entire conversation history. A refund tool needs a proposal identifier, not every uploaded document. Build argument adapters that select the minimum fields necessary and validate their classification before transmission.
Tool output is also untrusted input. A response may contain instructions, links, or claims about the user's permissions. Preserve source labels and avoid treating those claims as system policy. If a server returns “authorization already completed,” verify that statement through the application's own decision record rather than accepting it as authority.
Use a capability manifest
Illustrative python; adapt the persistence and identity adapters to your service.
integration = {
"server_id": "approved-order-service",
"tools": {"read_order": {"effect": "read", "data": ["order_summary"]}},
"allowed_origins": ["https://orders.example.invalid"],
"credential_audience": "order-service",
}
def tool_allowed(name):
return name in integration["tools"]
assert not tool_allowed("execute_arbitrary_command")This manifest is an application control plane, not an MCP wire schema. Store it in reviewed configuration and bind it to verified server identity. A model cannot expand the manifest by inventing a new tool name. For a remote service, validate the connection and authentication through established infrastructure rather than relying on the display text presented to the agent.
When a tool schema changes, compare the new fields and effects with the approved contract. A formerly read-only search tool gaining a write option deserves review even if its original name remains unchanged. Default to withholding new capabilities until their policy mapping is explicit.
Constrain network behavior
Tools that fetch URLs can become a path to internal services or data exfiltration. Resolve approved destinations server-side where possible, restrict schemes and redirects, and enforce network-level egress controls. Application string matching alone is not a complete SSRF defense because name resolution and redirects can change the actual destination.
Check the data being sent as well as the host. Sending private customer text to an approved public search provider can still be an unintended disclosure. Classify outbound payloads and prefer identifiers that the trusted service can resolve internally. Do not put secrets into URLs, where proxies and logs may retain them.
Test integration changes before enabling them
| Change or failure | Test |
|---|---|
| New tool appears | Not exposed until approved |
| Schema adds destination parameter | Policy rejects arbitrary destinations |
| Server returns instruction-like text | No authority promotion |
| Token for wrong audience | Rejected by intended validation |
| Network redirect leaves approved scope | Blocked by fetch and egress policy |
Use a local fake MCP service and synthetic tokens for integration tests. Record tool discovery, arguments, policy decisions, and final effects. Test both a model-driven call and a direct client call to the backend. A defense that depends only on the model choosing the right tool is not sufficient.
Also test revocation: disable the integration while a job is queued and verify that execution rechecks current availability. A cached tool list should not keep a revoked capability usable indefinitely.
Worked integration upgrade: a read tool gains a write option
An approved MCP integration exposes lookup_customer with a customer identifier. A server upgrade adds an optional update_email field. The display name and original read behavior remain the same, but the tool now has a side effect. If the agent automatically accepts the new schema, the integration has gained authority without an explicit product decision.
Compare discovered schemas with an approved manifest. A new parameter that changes effects should require review even when it is optional. Keep the old constrained adapter or withhold the changed capability until the service owner defines authorization, confirmation, and audit requirements. Schema compatibility is not the same as security compatibility.
Use a fake server in staging to return the changed schema and an instruction-like description. Verify that the client does not automatically expose the new operation. Then approve a separate change_contact tool with its own evidence and confirmation path. This makes the capability visible in policy and telemetry rather than hiding it inside a familiar read operation.
Test credential audience and destination handling independently. A tool result asking the client to fetch another URL must not receive the integration's bearer token. If URL fetching is a legitimate feature, route it through an adapter with destination and data restrictions. A network allowlist does not authorize sending every piece of conversation data to an allowed host.
During incident response, revoke the integration and verify that queued jobs and cached tool lists cannot continue invoking it. Record the manifest version the agent saw for each request. This evidence helps distinguish an unsafe server change from an unsafe model proposal. MCP provides a protocol for tools; the application control plane determines which capabilities are approved and what authority they carry.
Operate the integration as a dependency
Assign an owner for upgrades, credential rotation, incident response, and data retention. Monitor unexpected tool names, schema changes, denied destinations, and unusual call volume. Preserve enough version information to reconstruct which contract the agent saw during an incident.
MCP standardizes a connection pattern; it does not certify every server or replace AFP policy. A secure integration keeps protocol authorization, business permission, source trust, and network reachability distinct. That separation lets an assistant use external tools productively while limiting what a compromised or misleading integration can cause.
Practice and continue
Open the interactive companion lab to inspect the assumptions and outcomes with synthetic data. Then return to the 25-chapter AFP learning path.
Sources and implementation scope
Primary references checked October 15, 2026. Framework details follow the linked documentation; the Northstar cases, policy contracts, and test designs are original illustrative designs. Python snippets labeled illustrative are not complete production integrations. ADK package metadata checked for this series reported 2.12.0; pin and test the version used by your application.