Skip to main content
What this unit solvesFor anything a CLI can do, use the CLI first. MCP is the fallback, not the default. This unit covers the fundamental differences between CLI and MCP: token cost, composability, auditability, authentication, and state management. It explains why CLI-first is the more robust default strategy and gives you concrete criteria for when to fall back to MCP. A worked example of the same workflow over both paths puts numbers on the difference.

Learning objectives

  • Explain the fundamental differences between CLI and MCP across token cost, composability, auditability, authentication, and state management.
  • Articulate the case for CLI-first and give concrete composability advantages (pipe, --json, jq chaining).
  • Identify when to fall back to MCP (CLI unavailable, unauthenticated, rate-limited, or no CLI equivalent exists).
  • Avoid running CLI and MCP in parallel for the same operation, preventing state splits and token waste.

1. What CLI and MCP each are

CLI (Command Line Interface) refers to existing command-line tools: git, gh, docker, kubectl, psql, aws, npm, uv, make, jq, and so on. They write directly to stdout / stderr after invocation, with no additional protocol layer required. MCP (Model Context Protocol) is an open standard proposed by Anthropic in 2024 that defines how external tools and data sources are called by an LLM in a structured way [1]. An MCP server exposes three interface types — tools, resources, and prompts. An MCP client (such as Claude Code or Cursor) connects to the server and mounts its tools under the mcp__<server>__<tool> namespace. The positioning difference between the two:
CLIMCP
NatureThe tool itselfAn intermediary protocol layer for tool access
Primary consumerHumans (keyboard) + agents (via Bash tool)Agents (MCP client)
InteroperabilityAcross tools, languages, operating systemsAcross MCP-supporting clients, though the server/client matrix is still converging
MaturityDecadesTwo-plus years, spec still evolving
How Claude Code is designed around the Bash toolClaude Code lists Bash as one of its three core tool categories (alongside file modification and read-only tools) [2]. Read-only commands like ls, cat, grep, find, wc, which, and git status are built-in and require no permission prompt [2]. Other commands use Bash(specifier) allow / deny / ask rules. This design puts Bash in the most common, highest-priority position from the start.

2. Fundamental differences

2.1 Token cost

MCP’s fixed context cost: Once an MCP server connects, its tool schemas enter the model’s context. Even with tool search enabled by default (schemas load lazily), a tool that Claude has already discovered still consumes context on subsequent turns [1]. CLI’s variable context cost: CLI has no pre-loaded schema. The Bash tool’s schema is fixed and does not grow with what commands you run. The real cost appears only when stdout enters context, and stdout is under your control (trim it with head, tail, or jq -c '.[0]' beforehand). Rough order-of-magnitude estimate: a single MCP tool call costs “schema trigger + structured JSON response” together; an equivalent CLI call has zero schema cost, and the response can be trimmed to a single line of JSON. Against a 200k context window the difference looks small. Across a workflow run fifty times a day, the monthly gap is in the tens of thousands of tokens.

2.2 Composability

CLI is shell-native: Every CLI’s output can be piped into another CLI, enabling high-density information extraction.
# Find PRs created after 2026-05-01 with more than 5 reviews
gh pr list --state all --json number,createdAt \
  | jq -r '.[] | select(.createdAt > "2026-05-01") | .number' \
  | xargs -I{} gh pr view {} --json number,reviews \
  | jq -r 'select((.reviews | length) > 5) | .number'
MCP has no shell-level equivalent: Each mcp__<server>__<tool> call is independent. Output returns to context and Claude decides the next step. A four-step pipeline costs four schema triggers and four full responses.

2.3 Auditability

CLI commands are plaintext and recorded in shell history. auditd, syscall tracing, and bash history all provide audit trails. In CI, the run: blocks in git log are deterministic records. MCP calls happen at the agent execution layer and require extra logging infrastructure (hooks, subagent logs) to be traceable (see 04-6 Hooks for partial support — it is not the default). For high-compliance scenarios (finance, healthcare, academic review), CLI’s auditability is a structural advantage.

2.4 Authentication and state management

CLI piggybacks on OS-level authentication: gh auth login, aws configure, and gcloud auth login store tokens in the OS keychain or the appropriate ~/.config directory. Subsequent commands carry credentials automatically. Claude Code’s Bash tool allows fine-grained read control over credential files via permissions.deny [2]. MCP authentication is each server’s own responsibility: HTTP servers use OAuth (detailed in 04-9 MCP Integration); stdio servers receive keys via env. Most servers have no session state, though some (Notion editing, Atlassian changes) do. State management is correspondingly more complex and requires understanding each server individually.

3. Why CLI-first

Distilling the differences above into four concrete reasons:
  1. CLI is the ecosystem’s official, first-party path. gh is GitHub’s official CLI, kubectl is the official K8s CLI, aws is the official AWS CLI. Documentation is complete, versions are stable, community coverage is broad, and upstream changes land here first. Bypassing it means bypassing a maintained, well-lit road.
  2. Output format is under your control. gh pr list --json number,title,state selects exactly the fields you need. An MCP call returns the full structured object — the fields you want and the fields you do not all enter context together.
  3. No extra context consumed. The Bash tool schema is fixed. MCP tool descriptions grow linearly with the number of connected servers.
  4. Debugging path is clear. CLI failures produce a specific exit code and stderr. MCP failure diagnosis varies by server (protocol error, expired credentials, and nonexistent tool all look different).
There is no official “CLI first” directiveAs of 2026-06, Anthropic’s official documentation does not use the phrase “CLI first” in either the [permissions] or [MCP] sections [1, 2]. “CLI-first” is a practical strategy this Playbook derives from the official architecture: Bash is a core tool type, read-only commands need no prompt, and permissions are configurable down to the command prefix. Those design choices put Bash in the highest-leverage position — CLI-first is simply following the path that was already laid down.

4. When to use MCP (fallback trigger conditions)

CLI-first is the default. Switch to MCP only when at least one of the following is clearly true:
TriggerExample
The service has no CLI at allMany SaaS tools (early Notion, Linear, some Sentry features) expose only a REST API
CLI requires authentication that the agent environment cannot completeOAuth flow requires interaction; device code flow is not available
CLI has hit its rate limitMultiple clients share the same token pool; an MCP server can have its own independent pool
A single server needs to be shared across multiple MCP clientsSame server used by both Claude Code and Cursor, avoiding two separate configurations
The operation requires a structured, typed responseSchema validation is one of MCP’s design goals
Not “MCP works too, let’s try both”The fallback rule: switch only when a condition is clearly met. Do not install a server because “MCP might also work” — every additional server carries a permanent context cost, a permissions surface, and a supply-chain risk. Pick one path per workflow and do not go back to mixing them (next section).

5. Worked example: the same operation over CLI and MCP

5.1 Scenario

Query the latest 10 open PRs from a GitHub repo, listing number, title, author, and draft status.

5.2 CLI path

gh pr list --repo owner/repo --state open --limit 10 \
  --json number,title,author,isDraft \
  | jq -r '.[] | "\(.number)\t\(.title)\t\(.author.login)\tdraft=\(.isDraft)"'
Characteristics:
  • Single stdout output; pipe directly to | head, | wc -l, or | column -t for post-processing.
  • Failure exits non-zero with a clear stderr message (“API rate limit exceeded”, “auth required”).
  • Token cost: 0 schema loading + roughly 800 tokens of structured output (10 PRs as JSON).
  • From Claude’s perspective, the Bash tool schema is already resident — this call adds nothing.

5.3 MCP path

Assuming the official GitHub MCP server is installed (mcp__github__list_pull_requests):
Call mcp__github__list_pull_requests(owner='owner', repo='repo', state='open', per_page=10), then summarize the result
Characteristics:
  • Tool schema enters context (tool search means it loads on trigger, but once loaded it occupies context).
  • Returns a complete structured object, potentially including head, base, user, and other fields you will not use — typically 1,500-3,000 tokens.
  • A derived field like draft status requires Claude to compute it inside context.
  • Error messages when it fails vary by server design; some are not human-friendly.

5.4 Side-by-side comparison

DimensionCLI (gh)MCP (mcp__github__*)
Schema loading cost0 (shared Bash tool schema)Loaded each time the server connection is triggered
Response tokens per call~800 (lower after trimming)~1,500-3,000 (full object)
Composabilitypipe / jq / xargs / redirect to fileClaude must compute inside context
Auditabilityshell history / git log / auditdRequires hook or server log
DebuggingExplicit exit code + stderrDepends on server implementation
Authenticationgh auth login once, permanentOAuth token expires and must be renewed
Quantifying the differenceAssume this query runs 50 times a day. The CLI path burns roughly 0.6M tokens per month (response side); the MCP path burns roughly 2.3M tokens per month (schema + response). At Claude Sonnet 4.6 pricing, the monthly gap is a few dollars. Stack several servers and it becomes tens of dollars. CLI-first is not just about saving tokens — it is about preserving context budget for work that actually requires it.

6. Anti-pattern: mixing CLI and MCP

This is the most common source of silent bugs. A concrete scenario:
# You manually run this in your shell: create a PR
gh pr create --base main --head feature-x --title "WIP" --body "..."
At the same time, the agent receives “create a PR for me,” has no knowledge of your manual action, and proceeds via MCP:
mcp__github__create_pull_request(...)
Result: two PRs coexist with inconsistent messages; CI triggers once for the gh side and once for the MCP side. State has split. Rules:
  1. Pick one path per operation: if you use CLI today, stay on CLI; if MCP, stay on MCP — consistent across the session.
  2. Do not go back after a fallback switch: only switch to MCP when CLI is unavailable; do not “try both to see which works.”
  3. Document across sessions: add a line to CLAUDE.md — “This project uses gh CLI exclusively; no GitHub MCP server is installed” — to give every session a consistent starting default.

7. Tool comparison

ConceptAnthropic Claude (primary)OpenAI CodexGoogle AntigravityGitHub Copilot CLICursor (brief)
Official CLIclaude CLI (Claude Code) [1]codex CLIagy (Antigravity)gh + Copilot CLI extensioncursor CLI
Bash tool supportCore tool type (built-in read-only no-prompt) [2]ConfigurableConfigurableConfigurableConfigurable
MCP supportBuilt-in MCP client, .mcp.json config [1]Configurable [needs source verification]Configurable [needs source verification]Configurable [needs source verification]Built-in [needs source verification]
Authentication managementOS keychain + ANTHROPIC_API_KEY env var + sub-CLIs like gh carry their ownConfigurableConfigurableConfigurableConfigurable
Token budget controlTool search enabled by default [1]ConfigurableConfigurableConfigurableConfigurable
Official CLI-first guidanceImplied (Bash as core tool) [2]No explicit guidanceNo explicit guidanceNo explicit guidanceNo explicit guidance
Naming clarificationClaude Code’s Bash tool is the interface through which the agent calls the shell; the claude CLI is the command used to invoke Claude Code itself. They operate at different levels. For OpenAI Codex, Antigravity, and GitHub Copilot CLI, refer to each vendor’s current documentation for Bash tool and MCP details; entries marked “needs source verification” in the table require confirmation. Cursor is a third-party IDE (Anysphere) and appears here only for a brief reference column.

Hands-on exercises

30-minute practice
  1. Build a CLI-first checklist (10 minutes): list 10 operations common in your workflow (query issues, query PRs, run tests, view logs, query DB, deploy, etc.) and mark each “CLI available,” “needs MCP fallback,” or “built-in tool is enough.” This list becomes your default starting point next session.
  2. Compare both paths on the same operation (15 minutes): pick one operation you use often (such as fetching GitHub issues), complete it via CLI first (estimate token cost: use wc -w or wc -c to approximate stdout size), then complete it via MCP (observe how much context it actually consumes). Quantify the gap and decide which path becomes your default.
  3. Detect mixed usage (5 minutes): scan ~/.bash_history and recent session transcripts for signs of CLI and MCP being called in parallel for the same service. Flag any you find and decide whether to consolidate.

Common pitfalls

Anti-pattern list
  • Defaulting to MCP because “it’s AI-native and therefore more modern”: this ignores the structural advantages CLI has in composability and token cost. Newer does not mean better suited to your scenario.
  • Keeping MCP active out of inertia when a CLI exists: existing configuration is not a default. Evaluate the fallback trigger conditions for every new operation.
  • Running CLI and MCP in parallel for the same service within a session: silent source of state inconsistency bugs. Commit to one path.
  • Treating the Bash tool as a universal fallback and wrapping even simple grep calls as MCP servers: if the shell already does it, packaging it as MCP adds complexity for no gain. The opposite extreme of CLI-first is just as wasteful.
  • Not documenting a fallback switch in CLAUDE.md: the next session starts over with no memory of the decision. Write it into the rules file.
  • Treating gh pr list and mcp__github__list_pull_requests as fully equivalent: their token costs, auditability, and debugging paths differ. Equivalence is an illusion.

Self-check

The bar for passing this unit
  1. Facing a new integration requirement, can you decide “CLI available or need MCP” within 30 seconds? State your decision criteria.
  2. Can you list at least three concrete advantages CLI has over MCP? Give a real example for each.
  3. In your current session (or your most recent one), is there any instance of CLI and MCP being used in parallel for the same service? List them and decide whether to consolidate.
  4. Does your CLAUDE.md document a CLI-first preference? If not, add a line now.

Sources and further reading

Factual claims are grounded in official documentation; fast-changing items are annotated as of 2026-05.
  • [1] Anthropic, “Connect Claude Code to tools via MCP,” code.claude.com, 2026. [Online]. Available: https://code.claude.com/docs/en/mcp (as of 2026-06; MCP transport, scope, tool search)
  • [2] Anthropic, “Configure permissions,” code.claude.com, 2026. [Online]. Available: https://code.claude.com/docs/en/permissions (as of 2026-06; Bash tool as core tool type, read-only command list, allow / deny / ask rules with Bash(specifier) form, shell specifier syntax)