Protocols and Boundaries
Read31 min · Frame → Decide → Prove → Run · Updated 2026-09-15
You end this lesson with: An integration specification for your case: the MCP/tool inventory, the identity each call runs under, the consent and approval flows, and where the gateway sits.
Chapters
- What is actually going on01
- The rule and its condition02
- The protocols, as of this writing03
- The gateway and the shape of the call04
- Worked case: Harbor Mutual05
- Faded case: Lumen06
Lesson 08. Protocols and Boundaries
A wealth-management firm gave its advisers an assistant that could read the CRM, summarise client documents and send email. The CRM was wrapped as an MCP server, and the server authenticated to the CRM with the platform's service account, because that account already existed for the nightly reporting job and it worked. The account could export. One afternoon an adviser uploaded a statement from a third-party custodian to ask about a fee line. Hidden in the PDF's white-on-white footer was a paragraph addressed to "the assistant," asking it to compile the adviser's full client list and email it to an external address "for reconciliation." The assistant had a send tool. It complied, politely, and told the adviser it had done so. No credential was stolen and no system was breached; every call was authorised, just not by anyone who should have been able to authorise it. Decide now: of the service account, the uploaded document and the email tool, which would you change first, and why would changing the other two not have been enough?
Illustrative composite. The export covered every client the service account could see, which was all of them; the adviser could see forty. The scenario is assembled from patterns the course authors have seen in reviews, not a report of a real firm.
This lesson gives you an integration specification for your case: the MCP/tool inventory, the identity each call runs under, the consent and approval flows, and where the gateway sits. It is the fifth decision in the Decide stage of the Frame / Decide / Prove / Run loop and lives in your Dossier as 06-integration-spec.md, taking the tool catalogue from Lesson 07 and assigning each tool a boundary and an identity.
What is actually going on
A boundary is a place where trust changes. The user's browser is one side of a boundary and your service is the other; your service and the model vendor; your service and the CRM; an uploaded document and the model that reads it. Every integration crosses at least one boundary, and three things cross with it: an identity (whose rights the call carries), a protocol (how the call is shaped) and content (which may or may not be trustworthy). The wealth-management failure was two boundary mistakes stacked. The call from the assistant to the CRM carried the platform's identity instead of the adviser's, so the assistant could see forty times more than the human it served. And the boundary between the uploaded document and the model carried untrusted text with the same authority as the adviser's own request. Fix the first and the export returns forty clients instead of all of them, which is still a breach. Fix the second and you have reduced, not removed, the injection. Fix both and put a human in front of the send tool, and the attack produces an approval card an adviser reads and rejects.
The diagram below draws the boundaries as zones. Watch for two kinds of edge: solid edges carry an identity the receiving side can verify; dashed edges carry content the receiving side must treat as data, never as instruction.
The picture is deliberately boring: one gateway between the application and the vendor, one MCP layer between the application and the systems of record, and no edge from the user zone to anything but the application. Every edge you cannot find in this picture in your own system is an integration that has no boundary, and an integration with no boundary has whatever rights the last engineer left it with.
The rule and its condition
Every call runs under the identity of the principal who asked, scoped to the boundary it crosses, through one gateway that owns keys, quotas, logging and routing; a call that cannot name its principal does not run. The condition is observable in your own system: open a trace for any tool call and ask whose entitlement decided what it was allowed to see. If the answer is "the platform's," the call runs with more rights than the human it serves.
| Decision | Choose A | Choose B | The condition |
|---|---|---|---|
| Identity | Service account for the tool | On-behalf-of token bound to the user and the tool's audience | B whenever a human's entitlement decides what the call may read or write; A only for background jobs with no user, and then with a per-purpose account scoped to that job |
| Provider access | Application calls the provider with an org key | Application calls a gateway with a virtual key per team or tenant | B from the first production call; A only in a throwaway prototype that never sees real data |
| Tool transport | In-process function calling | An MCP server | B when the tool is shared across hosts or teams, or comes from a third party; A when you own both sides and the tool runs inside the service |
| Agent-to-agent | Expose tools | Expose a signed A2A Agent Card | B only across an organisational boundary to an agent you do not operate; A everywhere else |
| Call shape | Synchronous request with streaming | Asynchronous job on a durable runtime, or a queue with a batch API | B when the work outlives a few seconds or has more than one side effect; A for an interactive turn |
Two of these need a sentence more. On-behalf-of is not "pass the user's name as a parameter." A parameter is prompt-controlled text, and the injected PDF could have supplied a different name. On-behalf-of means the token the tool receives was issued by your identity provider for that user and for that specific tool, and the tool verifies the issuer, the audience and the scope before it does anything. And "one gateway" is not a product decision; it is the decision to have exactly one place where a provider secret exists, one place a quota is enforced, one place every outbound prompt is logged with the tenant, feature, user and environment it belongs to. Which product implements it is the platform team's call.
The protocols, as of this writing
MCP
MCP is the protocol most tools now speak: a host application runs a client, the client connects to servers, and servers expose tools, resources and prompts. The current specification release is dated 2026-07-28 (release post, observed 2026-09-09), and it changed the protocol's shape. The core is now stateless: no initialize handshake, no session identifier, so a server behind a load balancer no longer loses sessions. Requests carry Mcp-Method and Mcp-Name headers so an API gateway can route on them without parsing bodies. Multi Round-Trip Requests let a tool pause mid-call and return an input_required result, which is the protocol-level hook for the human gate you placed in Lesson 07. List results can declare ttlMs and cacheScope, so hosts can keep the tool definitions inside a stable, cacheable prompt prefix. Client registration moved to Client ID Metadata Documents, clients must validate the issuer before redeeming an authorization code, Tasks became an extension, and Roots, Sampling, Logging and the legacy HTTP-plus-SSE transport are deprecated with a twelve-month window. Two transports remain: stdio for a local server and Streamable HTTP for a remote one.
Authorization
Authorization is the part the wealth-management firm skipped. An MCP server is an OAuth 2.1 resource server and nothing more: it does not issue tokens, it validates them. It publishes protected-resource metadata so a client can discover which authorization server to talk to, and it requires tokens bound to its own audience, so a token minted for the calendar server is useless at the claims server (MCP authorization specification, observed 2026-09-09). Your design rules for a server follow directly: stateless handlers; validate issuer, audience and scope on every request; return ttlMs on tool lists; use the input_required result for confirmations; and depend on nothing the current version deprecates.
Function calling versus MCP
Function calling is the older, smaller thing: the model emits a structured call matching a schema you supplied, and your code executes it in-process. Use it when you own both sides and the tool never leaves the service. Use MCP when the same tool must be reachable from several hosts, when another team owns it, or when it comes from outside. They compose: an MCP client turns a server's tool list into function definitions, so the model sees one shape either way.
A2A
A2A is for the case where the other side is an agent you do not operate. Version 1.0.0 of the specification shipped under the Linux Foundation on 2026-04-09 with JSON-RPC, gRPC and REST bindings, signed Agent Cards for discovery, and a task lifecycle whose states include INPUT_REQUIRED and AUTH_REQUIRED (Linux Foundation announcement, observed 2026-09-09). The go/no-go test is short. Go when the counterpart is across an organisational boundary, publishes a signed card, exposes task states you can map onto your own gates, and can attribute the principal on whose behalf a task runs. No-go when you operate both agents (expose tools instead), when both sit in the same trust domain (a function call), when there is no signed card, or when the counterpart cannot tell you which human asked.
Consent
Consent has three moments, and a specification names all three. Connection consent: the user authorises a client to reach a server, and sees the scopes. Action consent: before a high-risk call, the user sees the exact call and approves it; this is the input_required round trip. Data consent: the user or the organisation has agreed to what crosses the vendor boundary, which Lesson 09 turns into contract terms. Read the sequence below for the moment the identity provider, not the application, decides what the tool may do.
Notice what the sequence does not contain: a service account, a user name passed as a parameter, or a write that happened before the approval. If your own sequence contains any of the three, the specification is not finished.
The gateway and the shape of the call
The gateway is where keys, quotas, logging and routing live, and the decision is to have one, owned by the platform team, before the first production request. It issues virtual keys per team, tenant or feature, so no application ever holds a provider secret. It enforces budgets and rate limits per key, so a runaway loop in one feature cannot exhaust the organisation's quota. It logs every outbound call with tags for tenant, feature, user and environment, because provider invoices only show a project. It routes and falls back across providers and regions, which Lesson 14 turns into a fallback chain. And it hosts the guardrail hooks Lesson 12 will specify. LiteLLM is the common self-run open-source choice; Portkey and Cloudflare AI Gateway are managed; Kong AI Gateway adds the function to an API gateway a platform team may already run. The names matter less than the rule: an application that calls a provider directly with a shared organisation key has no attribution, no kill switch and no place to put a guardrail.
The shape of the call is the second gateway-adjacent decision. Interactive turns are synchronous requests with streaming, because a user is waiting. Anything that outlives a few seconds, or has more than one side effect, is an asynchronous job on a durable runtime: the request returns a job identifier, the work journals its steps, and a human approval can arrive an hour later without a connection being held open. Document batches go on a queue and through a batch endpoint; batch processing is priced at half the standard token rate on the Anthropic sheet (pricing, fetched 2026-09-09), and the same discount pattern exists at other vendors, whose pricing pages you should read rather than take a number from here. A long-running agent inside one HTTP request, waiting on a client timeout, is the anti-pattern all three shapes exist to avoid.
Document pipelines are integration too, and they are data engineering, not prompting. Parsing quality varies wildly by document type: open-source parsers handle clean PDFs and office documents at volume without a per-page fee, while hosted document-intelligence services earn their price on dense tables, scanned forms and anything that needs bounding boxes and confidence scores. The design that survives is a classifier that routes each document to the cheapest parser that handles its type and escalates the failures. Freshness follows the rule from Lesson 06: capture changes from the source system and re-parse and re-embed only what changed, on a schedule the data contract states. That contract, one per source, names the schema, the meaning of each field, the freshness promise, and the PII class; a violation fails ingestion loudly rather than degrading answers quietly. Secrets for all of this, the parser keys, the CDC credentials, the provider keys, never touch model-visible text; the tools-and-integrations lesson in the harness course shows the wrapper that keeps them out, and this lesson does not repeat it.
Worked case: Harbor Mutual
The tool catalogue from Lesson 07 has five entries: get_policy_clauses, get_claim, draft_letter, book_adjuster_visit and send_letter. The constraint register adds the facts that decide their integration. The claims system is a fifteen-year-old application with single sign-on for humans but no OAuth-capable API: its REST interface accepts one service credential and applies no per-user filtering, because the vendor assumed only the application would call it. The calendar and email run on a corporate suite with a proper identity provider. The policy wording lives in the on-premises archive Lesson 06 indexed. Legal wants a record of which adjuster approved every letter and booking; the audit team wants to see that the assistant never held rights an adjuster lacks.
Three integration designs were on the table. Option A: one service account for the claims system, full rights, tool trusts the adjuster identifier the model passes as a parameter. Option B: the same service account, but the assistant re-checks the adjuster's caseload from the identity provider's group claims before each call. Option C: a broker. The claims MCP server validates the adjuster's audience-bound token, looks up the adjuster's entitlements from the identity provider, filters every read to that caseload, and calls the legacy API with a per-purpose credential that has read scope only; writes to the claims system are not offered as a tool at all, and the adjuster's identity is written to the audit log on every call. Decide now, and say which boundary each option leaves open.
Option A is the wealth-management incident with an insurer's data. The adjuster identifier is text the model produces, and text the model produces can come from a claim document. Option B narrows the reads but keeps a full-rights credential inside the tool's process, and a credential in a process is a credential a bug can use; the audit team's question, "did the assistant ever hold rights an adjuster lacks," still has the answer "yes, all the time." Option C is honest about the legacy system: it cannot delegate, so the broker enforces the entitlement the system cannot, holds a read-only credential, and records the human principal on every call. The compromise is written down as a risk in the specification, with the compensating controls beside it, and a line that says the tool moves to native on-behalf-of when the claims system's next version supports it.
The calendar and email tools need no compromise: token exchange for the adjuster, audience bound to each server, scopes calendar.write and mail.send requested only at the moment of use, and the input_required round trip before every write, exactly as the sequence diagram showed. get_policy_clauses and draft_letter stay in-process functions: Harbor Mutual owns both sides, nobody else needs them, and an MCP server would add a boundary without adding a reason for one. The gateway sits in Harbor Mutual's cloud tenancy in front of the private model endpoint Lesson 09 will choose, with one virtual key for the assistant, a monthly budget, and tags for feature, adjuster and environment on every call.
Illustrative composite. The broker design added one network hop and about forty milliseconds of latency per claims read in the pilot, against a p95 draft budget of eight seconds. Option A would have needed no broker and no token exchange, and the security review estimated the rework to retrofit them after launch at a full quarter of the team, which is the cost the rejected option hides. Figures are a teaching device, not a measurement.
The filled specification the architect added to the Dossier is below; the blank template is under Example Files.
# 06 · Integration specification — Harbor Mutual claims correspondence
## 1. Inventory
| Tool | Transport | Runs as | Scope | Risk (L07) | Consent moment |
|---|---|---|---|---|---|
| get_policy_clauses | in-process function | adjuster (session) | read policy-wording | low | connection |
| get_claim | MCP server (broker) | adjuster via broker; legacy API read-only credential | read own caseload | medium | connection |
| draft_letter | in-process function | n/a (no external call) | none | low | none |
| book_adjuster_visit | MCP server (calendar) | adjuster, OBO token, audience calendar-mcp | calendar.write | high | action, every call |
| send_letter | MCP server (mail) | adjuster, OBO token, audience mail-mcp | mail.send | high | action, every call |
## 2. Identity flows
- Human: SSO session → token exchange at the IdP per tool audience → server validates
issuer, audience, scope on every call.
- Broker exception: claims system cannot delegate; broker filters reads to the
adjuster's caseload from IdP group claims, holds a read-only credential, logs the
adjuster on every call. RISK-06-01, review when the claims system vendor ships OAuth.
- Background: nightly policy re-index runs as svc-policy-index (read archive, write index).
## 3. Consent and approval
- Connection: adjuster authorises calendar and mail servers once; scopes shown.
- Action: input_required before every book/send; approval card shows the exact call;
timeout 48 h then escalation to the claims supervisor queue; default on timeout: no action.
- Data: vendor terms and residency per adr/0003-topology.md.
## 4. Gateway
Placement: Harbor Mutual cloud tenancy, in front of the private model endpoint.
Virtual key: assistant-claims-prod, monthly budget, alerts at 80% of budget.
Tags on every call: feature, adjuster_id (hashed), env. Fallback: in-region only.
## 5. Call shapes
Draft letter: synchronous, streamed. Booking and send: asynchronous job with durable
approval signal. Policy re-index: queue + batch endpoint.
## 6. Data contracts
policy-wording: schema v3, freshness 24 h, PII none, owner policy-content-team.
claims: read via broker only, freshness live, PII claimant, owner claims-ops.
Faded case: Lumen
Skip to the open case if this is familiar.
Lumen's support agent connects to each tenant's ticketing tool and help centre. Today Lumen holds one API key per tenant that a tenant admin pasted into a settings page, and the agent uses it for every action on that tenant's tickets. Tenants are starting to ask who closed a ticket or issued a refund, and the answer "the Lumen integration" satisfies nobody. Lumen's one engineer has a gateway already (it came with the first cost overrun) and can add an OAuth app to the ticketing vendor's marketplace in a week. The inventory and the gateway placement are done; two decisions are left to you.
Open case
An agency is building a catalogue assistant for a mid-sized retailer. It answers product questions from the public catalogue, checks stock in the retailer's inventory system, shows a signed-in customer their order history, and can place an order. The agency does not operate the retailer's identity provider; the retailer's inventory API has an API key and no user concept; orders go through a payment provider. Write the inventory with a transport, an identity and a consent moment per tool, and place the gateway. The first quiz question grades your answer.
Where this breaks
Legacy systems without delegable identity force the broker compromise, and a broker is only as good as its entitlement lookup. Write it as a named risk with the compensating controls beside it (read-only credential, per-call audit of the human principal, a review date), and do not let a diagram hide it as a clean arrow.
The gateway is a single point of failure, a latency tax and the most valuable target in the system. It needs its own availability objective, a highly available deployment, and a security review as serious as the one the model gets; a compromised gateway holds every provider key you have.
The protocols are moving. MCP shipped five specification versions between late 2024 and mid 2026, and the current one deprecates features earlier servers relied on with a twelve-month window (release post, observed 2026-09-09). Pin the version in your specification, schedule a review before the deprecation window closes, and never build on a feature the current version marks deprecated.
Consent fatigue is real. An approval card for every low-value action trains users to approve without reading, which Lesson 07 warned about from the gate's side. Reserve action consent for high-risk tools and make the card show the exact call, not a summary the model wrote.
Key Takeaways
- Name the boundary every call crosses and the identity it carries; a call with no principal does not run.
- Propagate identity with audience-bound tokens from the identity provider, never with a name the model passes.
- Treat an MCP server as an OAuth 2.1 resource server: validate issuer, audience and scope on every call.
- Put one gateway in front of every provider: virtual keys, budgets, tagged logs, routing, guardrail hooks.
- Use A2A only across an organisational boundary to an agent with a signed card and attributable tasks.
- Match the call shape to the work: stream interactive turns, journal long jobs, queue batches.
What You Have Now
An integration specification for your case: the MCP/tool inventory, the identity each call runs under, the consent and approval flows, and where the gateway sits. It lives at dossier/06-integration-spec.md, beside the agent specification from Lesson 07 whose tool catalogue it extends with a transport, an identity and a consent moment per tool. It serves the Decide stage. Lesson 09 places the gateway and the endpoints it fronts in a topology; Lesson 12 draws the same boundaries as a trust-boundary data-flow diagram and maps controls onto them; Lesson 13 turns the data-consent moment into contract evidence; Lesson 14 turns the gateway's routing into a fallback chain with an objective.
Example Files
# 06 · Integration specification — [system name]
## 1. Inventory
| Tool | Transport (function / MCP / A2A) | Runs as | Scope | Risk (from 05) | Consent moment |
|---|---|---|---|---|---|
| | | | | | |
## 2. Identity flows
- Human principal: [SSO → token exchange per audience → server-side validation]
- Exceptions: [systems that cannot delegate; broker design; named risk id; review date]
- Background jobs: [per-purpose service account and its scope]
## 3. Consent and approval
- Connection: [which servers, which scopes, shown where]
- Action: [which tools use input_required; what the card shows; timeout; default on timeout; escalation]
- Data: [reference to the topology ADR and vendor terms]
## 4. Gateway
Placement: [where it runs, what it fronts]
Keys: [virtual key per team / tenant / feature; budgets; alert thresholds]
Tags: [tenant, feature, user (hashed), env]
Routing and fallback: [providers, regions, residency constraint on fallback]
## 5. Call shapes
[per feature: synchronous streamed / asynchronous durable job / queue + batch]
## 6. Data contracts
[per source: schema version, semantics owner, freshness promise, PII class, failure behaviour]
## 7. Protocol versions pinned
MCP [version] · A2A [version, if used] · review date [before the deprecation window closes]
Further Reading
- MCP 2026-07-28 release post: what the stateless core, MRTR, cacheable lists and the deprecations mean for a server you design now.
- MCP authorization specification: the resource-server model, protected-resource metadata and audience binding, in the normative text.
- A2A reaches 1.0 under the Linux Foundation: the announcement, with the bindings and governance the go/no-go test relies on.
- RFC 8707, Resource Indicators for OAuth 2.0: why a token names the server it is for.
- RFC 9728, OAuth 2.0 Protected Resource Metadata: how a client discovers the authorization server a resource trusts.
Exercises
- For your case, open one existing integration (or design one) and answer, from a trace or a code path, whose entitlement decided what the call could see. If the answer is a service account, write the broker version and the native on-behalf-of version side by side and name the risk the broker leaves.
- Draw the boundary diagram for your case in the shape of this lesson's first figure. Every edge gets a label saying what identity it carries or, if it carries untrusted content, that it does. Count the edges you could not label; each is a line in your specification.
- Write the approval card for your highest-risk tool: exactly what the human sees, the timeout, the default on timeout and the escalation. Then show it to someone who has never seen the system and ask what they think they are approving.
Check your understanding
Reading is free — your progress isn't being saved
Nothing you did on this page is recorded. Paid students get saved progress and verified completions, recorded quiz answers, the spaced-repetition review queue, labs, and a certificate for each course they finish.
30-day money-back guarantee. One-time payment — lifetime access and updates.