Terminal showing direct CLI commands for agent integrations
Engineering

CLI-First Agent Architecture

By Agents Squads · · 10 min

TL;DR — We replaced most MCP servers with direct CLI commands. The result: every agent action is readable in shell history, auditable without source-diving, and runs without persistent background processes. CLI-first trades protocol abstraction for transparency — and for most tools, it’s the better deal.

“Every command should be readable in shell history.”

Why CLI-First?

We used to run MCP servers. Lots of them. Chrome DevTools, Firecrawl, Supabase, custom servers for Gmail and Langfuse. They worked, but they added layers we couldn’t easily inspect.

Then we asked ourselves: Can we read every command our agents execute?

With MCP, the answer was no. Tool calls went through protocol handlers, spawned background processes, and produced results we had to trust. With CLI tools, the answer is yes. Every action is a shell command you can read, replay, and audit.

The Problem with Abstraction Layers

MCP servers solve a real problem—they give Claude access to external systems. But they introduce new ones:

Opaque execution. When Claude calls mcp__supabase__query, what actually happens? You’d need to read the server source code to know. With supabase db execute "SELECT * FROM users", it’s right there.

Persistent processes. MCP servers run continuously. They hold connections, consume memory, and can fail silently. CLI tools run on demand—invoke, execute, done.

Protocol overhead. Every MCP call involves JSON-RPC serialization, tool discovery, and response parsing. CLI tools are direct—stdin, stdout, exit codes.

Trust requirements. You’re trusting the MCP server to do what it says. With CLI, you can verify the exact command before it runs.

Key Takeaway — MCP’s core problem isn’t capability — it’s opacity. When Claude calls mcp__supabase__query, you need to read source code to know what happens. With supabase db execute "SELECT ...", the action is the command itself.

Our CLI-First Principles

The shift starts with direct commands over protocol wrappers. Instead of mcp__firecrawl__scrape({ url: "..." }), we use firecrawl scrape https://example.com --format markdown. The command is readable. You can run it yourself. You can pipe it, redirect it, combine it with other tools.

This makes data flow transparent. Every CLI command shows you what it’s about to do (the command itself), where data comes from (arguments, env vars), and where data goes (stdout, files). No black boxes. No hidden state.

Shell history becomes your audit log for free:

history | grep supabase
# See every database query your agents ran

Try doing that with MCP tool calls. And because CLI tools just work — no protocol negotiation, no capability exchanges — you save context tokens that MCP would waste on handshakes every session.

The Tools We Use Now

TaskMCP Server (Before)CLI Tool (Now)
Database queriesmcp__supabase__*supabase db execute
Web scrapingmcp__firecrawl__*firecrawl CLI or curl
Browser automationmcp__chrome-devtools__*playwright CLI
API callsCustom MCP serverscurl with proper headers
File operationsVarious MCP toolsNative shell commands

Practical Examples

Database Access

Before (MCP):

mcp__supabase__query({
  query: "SELECT * FROM metrics WHERE date > '2026-01-01'"
})

After (CLI):

supabase db execute \
  --project-ref "$SUPABASE_PROJECT" \
  "SELECT * FROM metrics WHERE date > '2026-01-01'" \
  --output json

Same result. But now you can:

Web Scraping

Before (MCP):

mcp__firecrawl__scrape({ url: "https://competitor.com/pricing" })

After (CLI):

curl -s https://competitor.com/pricing | \
  pandoc -f html -t markdown | \
  head -100

Or with Firecrawl CLI:

firecrawl scrape https://competitor.com/pricing --format markdown

Both are transparent. Both are auditable.

Browser Screenshots

Before (MCP):

mcp__chrome-devtools__screenshot({ url: "https://example.com" })

After (CLI):

playwright screenshot https://example.com --output screenshot.png

One command. Clear intent. Verifiable result.

When MCP Still Makes Sense

We’re not dogmatic. MCP has legitimate use cases:

For these, use MCP—but audit the server code and understand what it does.

Building CLI Wrappers

When a CLI tool doesn’t exist, we write simple shell scripts:

#!/bin/bash
# tools/langfuse-query.sh
# Direct Langfuse API query - transparent, auditable

set -e

LANGFUSE_HOST="${LANGFUSE_HOST:-https://cloud.langfuse.com}"

curl -sS -X GET "${LANGFUSE_HOST}/api/public/traces" \
  -H "Authorization: Bearer ${LANGFUSE_SECRET_KEY}" \
  -H "Content-Type: application/json" \
  --data-raw "$1"

Usage:

./tools/langfuse-query.sh '{"limit": 10}'

Every bit of this is readable. No hidden logic.

The Security Argument

CLI-first isn’t just about transparency—it’s about security.

Principle of least privilege: CLI tools run with the permissions of the invoking user. MCP servers often run with broader access.

Audit trails: Shell history is automatic. MCP logging requires deliberate implementation.

Code review: A bash script is reviewable by anyone. An MCP server is a full application.

Supply chain: CLI tools from package managers have established trust chains. MCP servers from npm can do anything.

Important — CLI-first isn’t just about developer convenience. It’s a security posture: least privilege by default, automatic audit trails via shell history, and reviewable bash scripts instead of full MCP server applications.

Migration Guide

Moving from MCP to CLI:

  1. List your MCP servers: What does each one do?
  2. Find CLI equivalents: Most have them (supabase CLI, gh CLI, aws CLI)
  3. Write wrapper scripts: For APIs without CLIs, wrap curl
  4. Update agent prompts: Teach agents to use shell commands
  5. Monitor and iterate: Some tools work better than others

The Result

Our agents now execute commands you can read:

$ history | tail -20
supabase db execute "SELECT COUNT(*) FROM executions"
gh issue list --repo agents-squads/hq --state open
curl -s https://api.langfuse.com/traces | jq '.data[0]'
playwright screenshot https://agents-squads.com --output og.png

Every action visible. Every command auditable. Every operation transparent.

That’s CLI-first.


This is part of the Engineering AI Agents series—practical patterns for building autonomous AI systems.

Related Reading

Back to Engineering