An itinerary agent needs to call local inventory tools and delegate a hotel-search task to an independently owned agent. What belongs on MCP versus A2A, and how would you handle capability discovery, task state, streaming, and errors across the boundary?
Put local inventory operations behind MCP and delegate the independently owned hotel search through A2A. Discover MCP tools through initialization and tool listing, discover the remote agent through its Agent Card, then persist A2A task identifiers, stream when supported, and distinguish transport, protocol, and business errors.
How to think about it
Put the itinerary agent’s local inventory lookups behind MCP: the agent is an MCP host and client, while inventory services expose typed tools. Put the independently owned hotel search behind A2A: the itinerary agent is an A2A client, the hotel agent is an A2A server, and the handoff is a durable task rather than a disguised function call.
The boundary is about semantics, not geography
MCP, the Model Context Protocol, standardizes how an AI application connects to tools, resources, and prompts. An MCP server might expose rail_search, museum_hours, or check_flight_inventory; the agent calls one with structured arguments and receives structured output.
A2A, the Agent2Agent protocol, standardizes how one agent communicates with another agent that may have a different owner, implementation, policy, and runtime. The caller does not see the other agent’s internal tools. It sends a message describing the work, receives a task, and later gets status, messages, or artifacts. An artifact is a durable output such as a hotel-results document.
That gives the useful first-pass rule:
| Question | MCP | A2A |
|---|---|---|
| What is being exposed? | A tool, resource, or prompt | An agent skill |
| Interaction shape | Call and return | Delegate and track |
| Typical trust boundary | One application or platform | Another agent or organization |
| Discovery | Initialization and list methods | Agent Card |
| Long-running work | Progress and cancellation, with version-dependent task support | Task lifecycle is central |
| Streaming | Transport or progress stream | Status and artifact events, commonly over SSE |
The word “local” is not the real deciding factor. MCP can run over remote HTTP, and an A2A agent can run on the same machine. The deciding questions are: is this an operation the orchestrator directly controls, or is it work delegated to an independently managed agent?
What discovery looks like
For MCP, the client first performs the protocol initialization handshake. That negotiates the protocol version and capabilities supported by both sides. The client then calls methods such as tools/list, resources/list, or prompts/list.
The important detail is that tools/list returns schemas, not merely names. The itinerary agent should inspect the input schema before calling rail_search. It should not assume that the date is called date, that the station uses an IATA code, or that the tool supports flexible tickets. Tool descriptions are part of the contract.
A minimal MCP call has this shape:
{
"jsonrpc": "2.0",
"id": 7,
"method": "tools/call",
"params": {
"name": "rail_search",
"arguments": {
"from": "Tokyo",
"to": "Kyoto",
"date": "2026-11-14",
"passengers": 2
}
}
}
tools/call is the MCP operation. rail_search is a deployment-defined tool name, so the client must discover it rather than hard-code it as a universal API.
For A2A, the client discovers the remote agent through its Agent Card, normally available at a well-known HTTPS endpoint such as /.well-known/agent-card.json. The card describes the agent’s identity, skills, supported input and output modes, protocol interfaces, authentication requirements, and capabilities such as streaming or push notifications.
The itinerary agent should check all of that before sending a request:
- Does the agent advertise hotel search, rather than hotel booking only?
- Does it accept structured JSON, plain text, or both?
- Does it support streaming?
- Does it require OAuth, an API key, or another authentication scheme?
- Does its advertised protocol version and endpoint match what the client supports?
An Agent Card is capability advertisement, not a security clearance and not a quality guarantee. The client still needs an allowlist, authentication, authorization, schema validation, and a policy for what customer data may leave the platform.
A concrete request
Suppose the user asks for two adults in Kyoto from November 14 to November 17, with a nightly budget under 220 dollars, free cancellation, and a location within one kilometer of Kyoto Station.
The itinerary agent might use MCP locally for rail inventory. That search returns in 400 milliseconds with two train options. The agent owns the connection, knows the tool schema, and can apply platform policy before displaying the results.
For hotels, it discovers an independently owned agent called Northstar Stays. The itinerary agent sends an A2A message containing the destination, dates, occupancy, budget, cancellation requirement, and distance constraint. It also includes a correlation identifier generated by the itinerary system.
Northstar may answer immediately with a message. More realistically, it creates a task because it needs to query several suppliers. The response gives the itinerary system a task identifier and a context identifier. The task identifier identifies this piece of work; the context identifier groups related messages in the same interaction.
The itinerary service persists that mapping:
itinerary_request 8f31
remote_agent northstar-stays
a2a_task_id task-42
a2a_context_id ctx-19
deadline 2026-08-28T09:00:12Z
The exact identifiers are illustrative. The production principle is not: never keep a remote task only in process memory. A container restart at 9:00 a.m. should not turn a perfectly good hotel search into a mystery.
Task state and streaming
MCP tool calls are usually request-and-response interactions. MCP also supports progress notifications and cancellation, and newer MCP versions or extensions may provide durable task primitives. Those features are useful, but they are still client-server mechanics. They do not by themselves describe an independently owned agent’s skill, identity, or business-level task lifecycle.
A2A makes that lifecycle explicit. A request can be accepted and remain in a working state. It may move to input-required if the hotel agent needs clarification, to completed with artifacts, or to failed, canceled, rejected, or authentication-required states depending on the implementation and negotiated version.
The itinerary service should persist every meaningful state transition. It should also define a deadline. “Working” for eight seconds is normal for a supplier search. “Working” for 47 minutes without a status update is an operational incident, not a reason to keep the user staring at a spinner.
If the Agent Card advertises streaming, use the A2A streaming operation and consume server-sent events. The hotel agent might emit:
- a working status update,
- an artifact update containing 18 candidate hotels,
- another artifact update after a second supplier responds,
- a completed status.
The user can see “18 options found” quickly, while the system continues collecting results. Every provisional result should carry its source and retrieval time. Hotel availability is not a promise; it can disappear between search and booking.
If the stream disconnects, do not send the original request again immediately. First retrieve the task state using the task identifier. If the remote agent supports push notifications, register a webhook for long-running work and authenticate that callback. A reconnect must be safe even when the original stream ended after the remote side accepted the request but before the client received the acknowledgement.
Errors across the boundary
Treat errors in layers.
A DNS failure, TLS failure, timeout, or HTTP 503 means the request may not have reached the remote agent, or may have reached it without the response getting back. A JSON-RPC error such as invalid parameters or an unknown method means the protocol request itself was wrong. A tool result marked with MCP’s isError flag means the tool ran but reported an execution failure. In A2A, an accepted request can produce a task whose state is failed, with a structured status message.
Do not flatten those into “hotel search failed.” The retry policy depends on the layer:
- Retry a bounded number of times for a transient 503, rate limit, or broken connection.
- Do not retry invalid arguments or missing permissions without changing something.
- After a stream failure, retrieve the existing task before retrying.
- Never blindly retry an operation that could create a booking or charge.
- Preserve the remote task identifier, error category, and trace identifier in logs, while removing passport numbers and other sensitive data.
An empty hotel result is usually a successful search with zero matches, not a protocol error. A supplier timeout may produce partial results, which the system should label as partial rather than quietly presenting them as complete.
The senior nuance
Do not expose the remote agent’s private tools directly to the model. Put an A2A adapter and policy gateway in front of it. The gateway validates the Agent Card, authenticates the connection, translates the user’s request into the remote agent’s accepted format, enforces data-sharing rules, and normalizes status and errors for the itinerary agent.
It is reasonable to wrap that adapter as a local MCP tool so the itinerary model has one simple tool surface. But the wrapper must preserve asynchronous behavior and task identifiers. A function called search_hotels that blocks for 60 seconds and hides the remote task state is a poor abstraction. It makes the code look simple while making recovery nearly impossible.
The reverse is also true. If the “independent hotel agent” is really a deterministic HTTP search service with no agentic behavior, A2A may be unnecessary ceremony. Use MCP or a normal service API when direct tool invocation is the honest model.
What they’ll ask next
Why not use MCP for everything?
MCP is excellent for exposing controlled capabilities to an application. It does not, by itself, solve cross-organization agent identity, skill discovery, durable delegation, or agent-level task state. An A2A adapter can still expose the remote agent as an MCP tool to the local model.
What happens when the remote Agent Card changes?
Cache it briefly, but refresh on connection failure, authentication failure, or schema mismatch. Pin trusted endpoints and validate the advertised authentication requirements. Capability discovery should reduce assumptions, not remove operational monitoring.
How do you stop a remote agent from abusing local tools?
Keep local MCP connections behind the itinerary agent. The remote agent receives only the minimum hotel-search data and cannot invoke local tools unless the platform explicitly brokers a separate, authorized operation. Treat every remote output as untrusted input and validate it before it reaches booking logic or the user.
One line to say in the room:
“MCP is the controlled tool boundary inside my application; A2A is the authenticated, task-oriented delegation boundary between agents, with discovery, durable state, streaming, and retries designed for each protocol rather than hidden behind one fake function call.”