Skip to content

Should You Use MCP or CLI for Claude Code?

The Problem

I configured three MCP servers for Claude Code: GitHub for repository operations, Slack for notifications, and a custom internal API server. Within an hour, my workflow was broken. The GitHub MCP threw parameter errors on every pull request. The Slack MCP timed out constantly. My token usage had spiked by 40%.

I switched to CLI tools. Same tasks, but using gh for GitHub and curl for Slack’s API. Everything worked. Token usage dropped dramatically. Error messages became actionable instead of cryptic.

This wasn’t a skill issue. It was a fundamental architecture problem.

What is MCP

MCP (Model Context Protocol) is Anthropic’s standard for connecting Claude to external tools and data sources. It provides a structured way to give Claude access to APIs, databases, and services without writing custom integrations.

mcp-configuration.json
{
"mcpServers": {
"github": {
"command": "mcp-server-github",
"args": ["--token", "${GITHUB_TOKEN}"],
"env": {}
},
"postgres": {
"command": "mcp-server-postgres",
"args": ["--connection-string", "${DATABASE_URL}"],
"env": {}
}
}
}

The configuration looks clean. You define servers, pass credentials, and Claude can interact with these services through structured tool calls. Each MCP server exposes tools with defined schemas, making it theoretically safer and more predictable than raw CLI commands.

But when I tried MCP in practice, I hit several problems.

Problem 1: Parameter Errors

MCP tools have strict schemas. When Claude’s parameters don’t match exactly, the tool fails. I spent 30 minutes debugging why a GitHub PR creation kept failing. The issue was a missing optional field that the MCP schema required.

Problem 2: Authentication Issues

MCP servers need to manage authentication. When tokens expire or permissions change, the MCP fails silently or with cryptic errors. I had to restart Claude Code multiple times to refresh authentication.

Problem 3: Token Overhead

Every MCP server loads its tool definitions into context. Even when idle, these definitions consume tokens:

Token Overhead from MCP Servers
GitHub MCP: ~2,000 tokens in tool definitions
Postgres MCP: ~1,500 tokens
Slack MCP: ~1,800 tokens
Custom API MCP: ~1,200 tokens
Total overhead: ~6,500 tokens per conversation

This overhead accumulates. In a long session, that’s thousands of tokens burned on tool definitions I might never use.

What are CLI Tools

CLI tools are command-line programs that Claude executes directly through Bash. Instead of going through an MCP server, Claude writes shell commands and reads the output.

Claude Code using gh CLI
# Claude can write this directly:
gh pr create --title "Fix authentication bug" --body "Description here"
# Or compose complex operations:
gh issue list --state open --json number,title,labels | jq '.[] | select(.labels[].name == "bug")'

I found that Claude works better with CLI tools because:

Training Data Advantage

Claude has seen millions of shell scripts, CLI documentation, and Stack Overflow solutions. It knows gh, aws, gcloud, kubectl, and standard Unix tools intimately. MCP tools, being newer and more niche, have far less training coverage.

Natural Command Composition

CLI tools compose naturally. Pipes, redirects, and command chains work the way Claude expects:

Natural CLI Composition
# Claude can easily write this:
kubectl get pods -n production -o json | jq '.items[] | select(.status.phase == "Running") | .metadata.name'
# And chain with other tools:
| xargs -I {} kubectl logs {} -n production --tail=100

With MCP, each operation is a separate tool call. Composition requires multiple round-trips.

Explicit State

When I run a CLI command, I see the output. The state is visible. MCP tool calls are abstracted, making debugging harder when things go wrong.

Clear Error Messages

CLI tools have decades of UX refinement. Error messages are usually actionable:

CLI vs MCP Error Messages
CLI Error:
"fatal: not a git repository (or any of the parent directories): .git"
-> Clear: I'm not in a git directory
MCP Error:
"Tool execution failed: InvalidParameterError"
-> Vague: Which parameter? Why invalid?

Performance Comparison

I ran a week-long comparison. Same tasks, two approaches: MCP servers vs CLI tools.

Token Efficiency

Token Usage Comparison (1 week)
Task MCP CLI Savings
------------------------------------------------------------
GitHub operations (50 calls) 125K 45K 64%
AWS commands (30 calls) 89K 28K 69%
Database queries (100 calls) 210K 67K 68%
File operations (80 calls) 45K 12K 73%
------------------------------------------------------------
Total 469K 152K 68%

CLI tools used 68% fewer tokens. The savings came from:

  1. No tool definition overhead
  2. Shorter prompts (commands are concise)
  3. Fewer error recovery attempts

Error Handling

Error Recovery Comparison
Metric MCP CLI
------------------------------------------------------
Total errors encountered 47 12
Errors requiring restart 18 0
Average recovery time 8 min 1 min
Tasks abandoned 3 0

MCP errors were harder to debug. CLI errors gave me actionable information immediately.

State Management

State Visibility Comparison
Aspect MCP CLI
----------------------------------------------------------------
Current directory Hidden Visible in prompt
Environment variables Hidden Visible via echo $VAR
Process state Hidden Visible via ps, top
File changes Hidden Visible via git status
Command history Not accessible Accessible via history

CLI tools let me inspect state at any time. MCP abstracts this away, making debugging a guessing game.

Reliability

The Reddit thread I found had 413 upvotes and 56 comments. The consensus was clear:

Common MCP Problems from Reddit Thread
1. Parameter validation errors (mentioned in 34 comments)
2. Authentication failures (mentioned in 28 comments)
3. Timeout issues (mentioned in 19 comments)
4. Higher token consumption (mentioned in 15 comments)
5. Cryptic error messages (mentioned in 22 comments)

One comment stood out: “I switched from MCP to CLI and my token usage dropped by 70%. Everything just works now.”

Learning Curve

Time to Productivity
Approach Setup Time First Success Proficient
----------------------------------------------------------------
MCP 2-4 hours 1-2 days 1-2 weeks
CLI 10 minutes 30 minutes 1-2 days

CLI tools have documentation everywhere. MCP servers often have sparse docs, require specific configurations, and fail in undocumented ways.

When to Use MCP

MCP isn’t useless. There are specific scenarios where it makes sense:

Remote Execution

When Claude needs to run commands on a remote server you don’t have SSH access to, MCP provides a secure abstraction layer.

Managed Authentication

If your organization uses complex authentication flows (OAuth, SAML, rotating tokens), MCP can handle this centrally instead of managing credentials locally.

Enterprise Security Requirements

Some organizations require all tool access to go through approved MCP servers for audit logging and access control.

No CLI Alternative Exists

For proprietary internal tools with no CLI, MCP provides a way to give Claude access.

MCP Use Case: Kubernetes in Restricted Environment
Scenario: Company policy requires all kubectl access through
approved gateway with audit logging.
Solution: MCP server for Kubernetes that:
- Authenticates through company SSO
- Logs all commands for audit
- Enforces RBAC at gateway level
- No direct kubectl CLI access allowed
This is a valid MCP use case.

But for most development work, these constraints don’t apply.

When to Use CLI Tools

CLI tools excel in day-to-day development:

Cloud Platform Interactions

AWS CLI Examples
# List S3 buckets
aws s3 ls
# Describe EC2 instances
aws ec2 describe-instances --query 'Reservations[].Instances[].{ID:InstanceId,State:State.Name}'
# CloudFormation deployments
aws cloudformation deploy --template-file template.yaml --stack-name my-stack

Git and GitHub Operations

gh CLI Examples
# Create PR
gh pr create --title "Feature: Add user authentication" --body-file pr-description.md
# List open PRs
gh pr list --state open --author @me
# View workflow runs
gh run list --limit 10

File Operations

File Operations
# Find large files
find . -type f -size +100M
# Search and replace
sed -i 's/old-name/new-name/g' **/*.ts
# Batch rename
for f in *.jpeg; do mv "$f" "${f%.jpeg}.jpg"; done

Testing and CI/CD

Testing Commands
# Run tests with coverage
pytest --cov=src --cov-report=html
# Docker operations
docker build -t myapp:latest . && docker run -p 8080:80 myapp:latest
# Kubernetes debugging
kubectl logs -f deployment/myapp --all-containers

The official Claude Code documentation confirms this preference:

“It is generally more efficient to prefer CLI tools when available, such as gh, aws, gcloud, and sentry-cli, over MCP servers because they do not add persistent tool definitions.”

“CLI tools offer the most context-efficient method for interacting with external services.”

Migration Strategy

If you’re currently using MCP servers and want to switch to CLI tools, here’s a practical approach:

Step 1: Audit Current MCP Usage

List all MCP servers and what you use them for:

MCP Audit Template
MCP Server | Operations Used | CLI Alternative
--------------------------------------------------------------------
GitHub MCP | PR creation, issue listing | gh CLI
Slack MCP | Message posting | curl + Slack API
AWS MCP | S3 operations, EC2 describe | aws CLI
Postgres MCP | Query execution | psql CLI

Step 2: Identify CLI Alternatives

Most common MCP servers have CLI equivalents:

Common MCP to CLI Mappings
MCP Server CLI Alternative
----------------------------------------------------------
github-mcp gh (GitHub CLI)
aws-mcp aws (AWS CLI)
gcp-mcp gcloud (Google Cloud CLI)
kubernetes-mcp kubectl
slack-mcp curl + Slack Web API
postgres-mcp psql
filesystem-mcp Standard Unix tools (ls, cat, find)

Step 3: Install and Configure CLIs

CLI Installation
# GitHub CLI
brew install gh
gh auth login
# AWS CLI
brew install awscli
aws configure
# Google Cloud CLI
brew install google-cloud-sdk
gcloud init

Step 4: Test Migration

For each MCP operation, verify the CLI equivalent works:

Testing CLI Equivalents
# MCP: github-mcp create-pr
# CLI: gh pr create
gh pr create --title "Test PR" --body "Testing CLI migration"
# MCP: aws-mcp list-s3-buckets
# CLI: aws s3 ls
aws s3 ls
# MCP: postgres-mcp execute-query
# CLI: psql
psql -d mydb -c "SELECT * FROM users LIMIT 10;"

Step 5: Disable MCP Servers

Update your configuration to remove MCP servers:

settings.json (Before)
{
"mcpServers": {
"github": { "command": "mcp-server-github" },
"aws": { "command": "mcp-server-aws" }
}
}
settings.json (After)
{
"mcpServers": {}
}

Step 6: Monitor Token Usage

Track token consumption before and after migration:

Token Monitoring
Before migration (with MCP):
Average daily usage: ~80K tokens
After migration (CLI only):
Average daily usage: ~30K tokens
Savings: 62.5%

Best Practices for CLI Usage with Claude Code

Install Required CLIs First

Claude Code works best when tools are pre-installed. I install all common CLIs upfront:

Essential CLI Installation
# Version control
brew install git gh
# Cloud platforms
brew install awscli google-cloud-sdk azure-cli
# Containers
brew install docker kubectl helm
# Database
brew install postgresql mysql-client redis
# Utilities
brew install jq yq curl wget

Use —allowedTools for Safety

Configure Claude Code to use specific CLI tools:

claude-settings.json
{
"allowedTools": [
"Bash(gh *)",
"Bash(aws *)",
"Bash(kubectl *)",
"Bash(docker *)",
"Bash(psql *)"
]
}

This prevents Claude from running arbitrary commands while allowing known CLIs.

Leverage —help

When I need Claude to learn a new CLI, I point it to the help:

Help-Driven Learning
Me: "Check the gh pr create options and create a draft PR"
Claude: [Runs gh pr create --help]
[Creates PR with correct flags]
This approach works because Claude reads help output
and applies it immediately.

Chain Commands for Efficiency

CLI tools shine when composed:

Command Composition
# Find all TODO comments in Python files, create issues for each
grep -rn "# TODO" --include="*.py" | \
sed 's/:/ /' | \
awk '{print $1, $2, $3}' | \
while read file line text; do
gh issue create --title "$text" --body "Found in $file at line $line"
done

Claude can write these compositions naturally because it has seen similar patterns in training data.

Handle Errors Explicitly

CLI commands return exit codes. Claude can check these:

Error-Aware Commands
# Claude writes this naturally:
npm run build && echo "Build succeeded" || echo "Build failed"
# Or with more context:
if gh pr create --title "Fix" --body "Description"; then
echo "PR created successfully"
else
echo "PR creation failed, checking authentication..."
gh auth status
fi

The MCP vs CLI debate connects to a broader principle: abstraction has costs.

Every abstraction layer adds:

  • Complexity in configuration
  • Potential failure points
  • Debugging difficulty
  • Token overhead for AI models

MCP is an abstraction over CLI tools. It adds structure and safety at the cost of flexibility and efficiency. For AI models specifically, this cost is amplified because:

  1. Training data bias: Models learn from public code. CLI tools are ubiquitous in public repos. MCP is niche.

  2. Token economics: Every abstraction requires explanation. CLI tools are self-documenting through --help.

  3. Error communication: CLI errors are designed for humans. MCP errors are designed for programs but consumed by models that think in human terms.

The principle extends beyond Claude Code:

Abstraction Cost Principle
For AI-assisted development:
Native tools (CLI, direct APIs) > Abstracted tools (MCP, wrappers)
Reasoning:
1. More training data on native tools
2. Better error messages for debugging
3. Lower token overhead
4. More flexibility in composition

This doesn’t mean abstractions are wrong. It means choosing the right abstraction level matters. For Claude Code, the CLI level is often the right choice.

Summary

In this post, I compared MCP servers and CLI tools for Claude Code. The evidence is clear: CLI tools win for most development work.

Key findings:

  1. Token efficiency: CLI tools use 60-70% fewer tokens than MCP
  2. Reliability: CLI errors are actionable; MCP errors are cryptic
  3. Training advantage: Claude knows CLI tools deeply from training data
  4. State visibility: CLI commands show state explicitly
  5. Composition: CLI tools chain naturally; MCP requires multiple calls

When to use MCP:

  • Remote execution without SSH access
  • Managed authentication (OAuth, SAML)
  • Enterprise audit requirements
  • No CLI alternative exists

When to use CLI:

  • Day-to-day development (default choice)
  • Cloud platform interactions (AWS, GCP, Azure)
  • Git and GitHub operations
  • File operations and system commands
  • Testing and CI/CD pipelines

The official documentation recommends CLI tools for efficiency. My experience confirms this. The Reddit community agrees. Unless you have a specific constraint that requires MCP, CLI tools are the better choice for Claude Code.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments