One agent, four kinds of connection
- Direct API toolyour code wraps one service
- CLI via shell
gh,aws,kubectl - MCP serverstandard, reusable tools and data
- Remote agent (A2A)delegate a task, get artifacts
What each mechanism actually is
A direct API tool is a tool definition you write in your own application. Claude asks for it by name, your code calls the service (REST, SQL, a queue) and returns the result. You own the schema, the auth and the error handling. Nothing about it is reusable outside your app unless you make it so.
A CLI integration means the agent has a shell and runs existing command-line tools. The Claude Code best-practices page calls CLI tools the most context-efficient way to reach external services, and recommends telling Claude to use tools like gh, aws, gcloud and sentry-cli. Claude already knows many of them and can learn others from their --help output. The cost is that you now need a shell, which needs permissions and sandboxing.
MCP (Model Context Protocol) is an open standard for exposing tools, data and prompt templates to any AI application that speaks it. You build the server once and every MCP host can use it: Claude Code, Claude Desktop, an IDE, your own agent. A2A (Agent2Agent), now governed by the Linux Foundation, is a standard for one agent to discover another agent and delegate work to it. The A2A docs draw the line cleanly: MCP is for agent-to-tool communication, A2A for agent-to-agent.
| Direct API tool | CLI | MCP | A2A | |
|---|---|---|---|---|
| Other end is… | A service you call | A program on the host | A tool or data server | An agent that reasons |
| Interface defined by | You, per app | The CLI’s own flags | The MCP spec | The A2A spec + Agent Card |
| Reuse across apps | Low | Any agent with a shell | High — any MCP host | High — any A2A client |
| Who plans the steps | Your agent | Your agent | Your agent | The remote agent |
| Typical unit of work | One call | One command | One tool call | A task with a lifecycle |
| Main risk | Duplicate glue code | Shell access | Context bloat, server trust | Opaque behaviour, latency |
MCP: hosts, clients, servers and the transports
In MCP the host is the AI application. It creates one client per server it connects to, and each client keeps a dedicated connection. Servers offer three features: tools the model can execute, resources that supply context and data, and prompts that act as templates for users. Messages are JSON-RPC 2.0 over one of two standard transports. stdio launches the server as a local subprocess and talks over its standard streams; it usually serves one client. Streamable HTTP sends each message as an HTTP POST to a single endpoint; it is how remote servers serve many clients, and it supports ordinary HTTP authentication, with OAuth recommended.
That transport choice is an architecture decision in itself. A stdio server runs with the user’s own permissions on their own machine: good for a filesystem or a local database, awkward to govern across a company. A remote Streamable HTTP server is deployed once, patched once, sits behind your identity provider and logs every call centrally. For an enterprise integration used by hundreds of people, that usually wins.
When MCP is right, and when it is overhead
MCP earns its place when the same capability is needed by more than one application or team, when a vendor already publishes an MCP server, or when you want the host (Claude Code, Claude Desktop, an IDE) to handle discovery and user consent for you. It is overhead when one application needs one internal call: a direct tool definition is less code, one less process to run, and one less network hop.
Two costs deserve scrutiny. First, context: every connected server’s tool definitions compete for the context window, and Anthropic’s code-execution post describes agents connected to hundreds or thousands of tools paying heavily for definitions up front (3.8 covers the remedy, loading them on demand). Second, trust: the spec asks hosts to treat tool descriptions and annotations as untrusted unless the server is trusted, and to get user consent before invoking tools. A third-party MCP server is code you are choosing to let your agent call.
# The MCP connector is a beta feature: check the current header in the docs.
response = client.beta.messages.create(
model=MODEL,
max_tokens=2048,
betas=["mcp-client-2025-11-20"],
mcp_servers=[{
"type": "url", # remote servers only; no stdio
"url": "https://mcp.example-crm.com/mcp",
"name": "crm",
"authorization_token": crm_token, # OAuth bearer token you obtained
}],
tools=[{
"type": "mcp_toolset",
"mcp_server_name": "crm",
"default_config": {"enabled": False}, # allowlist pattern:
"configs": {"search_accounts": {"enabled": True},
"get_account": {"enabled": True}}, # read-only tools only
}],
messages=[{"role": "user", "content": question}],
)The connector saves you writing an MCP client, but read its limits before choosing it. It supports only the tools part of MCP, not resources or prompts. It can reach only publicly exposed HTTP servers, not local stdio ones. And it is not eligible for zero data retention, because tool definitions and results are retained under the standard policy. In a regulated setting, that last point can decide the design.
CLI and code execution: the context-efficient path
When the agent already has a sandboxed shell, a mature CLI is often better than any wrapper. gh pr list --json number,title --limit 20 returns exactly the fields asked for; the model composes commands, pipes output through jq or grep, and only the filtered result enters context. Anthropic’s code-execution post generalises this to MCP itself: present MCP servers to the agent as code APIs in a filesystem, let the agent write code that calls them, and filter data before it reaches the model. Its worked example drops from about 150,000 tokens to about 2,000. The post is equally clear about the price: you need a secure sandbox with resource limits and monitoring, which direct tool calls avoid.
Which mechanism fits this connection?
- One service, one appDirect API toolleast moving parts
- Mature CLI, sandboxed shellCLI via Bashcompact, composable output
- Many apps or teams reuse itMCP serverbuild once, any host
- Another team’s reasoning agentA2A delegationhand off a task
Agent-to-agent: delegating to something that thinks
A2A is for when the thing on the other end is itself an agent: it reasons, plans, keeps state and may need a multi-turn conversation. Its core objects are the Agent Card, a JSON document describing an agent’s identity, endpoint, skills and authentication (published at /.well-known/agent-card.json); the Task, a stateful unit of work with an ID and lifecycle; Messages made of Parts; and Artifacts, the outputs. Clients can poll, stream updates over SSE, or receive push notifications to a webhook, which suits jobs that take minutes or hours. Version 1.0 defines JSON-RPC, gRPC and HTTP+JSON bindings, and adds cryptographic signing of Agent Cards.
The design principle to remember is opacity: agents collaborate without sharing their internal memory, tools or logic. That is the feature and the cost. You cannot see or constrain how the remote agent reaches its answer. You evaluate it by its outputs and its contract, the way you would a subcontractor. Task states such as input-required and auth-required tell you the remote agent can pause and ask for more, so your side must handle that, not just success or failure.
A2A on the outside, MCP on the inside
Traps the wrong answers are built from
| Tempting but wrong | Do this instead |
|---|---|
| Standardising on MCP for every integration, including one-off internal calls | Use a direct tool for a single-app integration; build an MCP server when reuse across apps or hosts is real. |
| Exposing a stateless function (scoring, lookup, conversion) as an A2A agent | Keep it a tool; reserve A2A for delegating goals to agents that plan and keep state. |
| Building a custom wrapper when a mature CLI and a sandboxed shell already exist | Let the agent use the CLI and filter output before it reaches context. |
| Choosing the MCP connector without reading its limits | Check it supports what you need: tools only, remote HTTP servers only, and not zero-data-retention eligible. |
| Treating a third-party MCP server’s tool descriptions as trustworthy by default | Vet the server, scope its tools, and require consent or permissions before tool calls. |
You should now be able to
- Describe what sits on the other end of direct API tools, CLIs, MCP servers and A2A agents.
- Choose between stdio and Streamable HTTP MCP transports for local versus shared, governed deployments.
- Justify MCP by reuse across applications and hosts, and reject it where a direct tool is simpler.
- Recognise when a CLI or code execution is the most context-efficient path, and what sandboxing it requires.
- Identify when a partner system should be reached as an A2A agent, and handle its task lifecycle.
- Spot where the current MCP specification differs from older, stateful descriptions.