MCP vs Skills: Why CLI + Skill Wins the Agent Toolchain
MCP servers burn 50K tokens where a 200-token SKILL.md does the same job. Why Perplexity, YC, and my own stack moved to CLI + Skills — and when MCP still wins.
MCPAgent SkillsCLIAI AgentClaude Code
3300  Words
2026-07-10

In March 2026, Perplexity’s CTO announced internally that the company was moving away from MCP and back to APIs and CLIs. The same week, Y Combinator president Garry Tan posted that “MCP sucks honestly” — too much context window, clunky auth, servers you have to toggle on and off — and that he’d vibe-coded a CLI wrapper for Playwright in 30 minutes that worked better than the MCP integration he was replacing. I didn’t need either of them to convince me. On a single day last week, my own agent stack hit three MCP failures in a row, and all three were rescued by the same thing: a plain script driving a plain CLI, orchestrated by a Markdown file. This post is my attempt to turn that experience into a usable judgment: in the MCP vs Skills debate, CLI + Skill has won the trunk of the agent toolchain, and MCP is retreating to a niche. I’ll show you the evidence, the honest counter-case, and a migration framework you can apply to your own stack today.
The Quarter the Tide Turned Against MCP
For most of 2025, MCP was sold as the TCP/IP of the agent era — one protocol to connect every tool to every model. The pitch was seductive because it solved a real 2024 problem: models couldn’t reliably use tools, and a standardized schema format helped. But by early 2026 the problem had inverted. Models got very good at using tools; what they couldn’t afford anymore was the cost of MCP’s way of describing them. And the people saying so out loud were not anonymous grumblers.
The receipts are specific. Sentry’s David Cramer — who built Sentry’s own MCP server, so this is not an outsider’s take — wrote that “many MCP servers don’t need to exist” because they are either poor API wrappers or replaceable by a skill file. Garry Tan’s complaint was even more concrete: the MCP-based browser integration ate his context window, the auth was painful, and a half-hour CLI wrapper beat it — only for his team to tell him Vercel had already shipped one. Which tracks, because Vercel CEO Guillermo Rauch had already framed the whole shift in one line: CLIs are the de-facto MCPs for agents. Then Perplexity made it institutional — Denis Yarats’ internal announcement, followed by the launch of their Agent API, positioned APIs as the substrate and MCP as an optional layer, not the foundation.
What makes this wave different from ordinary tech-Twitter contrarianism is who is doing the abandoning: the people who built MCP servers, shipped MCP integrations, and bet product roadmap on the protocol. When your earliest adopters start describing your standard as overhead, that’s not a marketing problem. That’s a unit-economics problem. Even Anthropic — MCP’s creator — published an engineering post on code execution with MCP acknowledging that loading full tool definitions into context doesn’t scale, and proposing that agents write code against MCP tools instead of calling them directly. Read that carefully: the protocol’s own author now recommends putting a code layer between the model and the protocol. The market read it the same way I do — the model wants to write commands, not speak JSON-RPC.
Three MCP Failures in One Day: A Field Log
Industry quotes are cheap. Here’s what actually happened in my own toolchain, in one working day, while doing completely mundane blog-operations work. I’m recounting these in detail because the pattern matters more than any single failure.
Failure one: the browser MCP that couldn’t reach my browser. I wanted to pull Google Search Console data for this blog — a task I’d done manually a hundred times in a logged-in Chrome session. The obvious-seeming move was the chrome-devtools MCP server: it exposes navigation, clicking, and network inspection as tools. Except the MCP server spun up its own isolated Chrome instance with a fresh profile — no cookies, no login state. Fine, I thought, I’ll log in. Google’s automation detection blocked the sign-in flow. I tried attaching to my real browser instead; tab targeting misfired, clicks landed on the wrong page. After forty minutes of fighting the abstraction, I deleted the MCP config and wrote roughly 60 lines of puppeteer-core that connect directly to Chrome’s debugging port on my already-logged-in profile — the same port-9222 technique I documented in my Chrome DevTools MCP setup guide. It worked on the first run. The MCP layer hadn’t just failed to help; it had actively inserted an isolation boundary between me and a resource I already had.
Failure two: the MCP server that no longer exists. My blog cover images used to be generated through Rube, a hosted MCP aggregator that proxied Gemini’s image API. Rube shut down. Not degraded — gone. Every workflow that routed through it died on the spot. The fix took an afternoon: a ~100-line Python script that calls the Gemini API directly, renders at 4K, and downsamples to a 1200×630 WebP. It’s faster than the MCP path ever was, it supports resolutions the proxy never exposed, and its only dependency is an API key in my environment. That script has now outlived the “infrastructure” it replaced, and it will outlive the next one too, because a script’s dependency graph is python + requests + one API, while a hosted MCP server’s dependency graph includes someone else’s business model.
Failure three: realizing the browser was never the right tool. After failure one, I stepped back and asked why I was driving a browser at all. Search Console and Google Analytics both have official APIs with service-account auth. The end state is a headless script authenticated by a personal service account, run by cron every week, dumping data my agent reads as plain files. No MCP, no browser, no login state to break. The lesson generalizes: a surprising fraction of MCP servers exist to wrap things that already have a scriptable interface one layer down.
Three failures, one diagnosis. In each case the MCP layer was either a fault point (isolation, flaky targeting) or a disappearing dependency (a hosted server that folded), while the layer beneath it — CLI, script, official API — was permanently available. The CompanyOS builders put this exact property into words: their skills survive MCP outages, because when a server disconnects you downgrade from automatic to manual, but the workflow knowledge survives. I used to nod at that line. Now I’ve lived it three times in one day.
Why CLI Is the Model’s Native Tongue
The deepest argument for CLI isn’t operational, it’s linguistic. A large model’s training corpus contains billions of lines of shell commands with their outputs — Stack Overflow answers, GitHub issues, CI logs, dotfiles, tutorials. When an agent runs gh pr list --state open --json title,author, it is doing something it has seen literally millions of times, including the error messages and how humans recovered from them. When the same agent calls an MCP tool, it is following a schema it first saw thirty seconds ago in its own context window. One of these is native fluency; the other is reading the instruction manual at the workbench. This is why “just let it use the CLI” keeps outperforming carefully engineered tool definitions: you’re not teaching the model a new skill, you’re getting out of the way of one it already has.
Then there’s the arithmetic, and it’s brutal. The essay Markdown is the New API documented the canonical example: GitHub’s official MCP server initially consumed on the order of 50,000 tokens of context just to describe its tools (later trimmed to roughly 23,000), while a SKILL.md file that says “use the gh CLI, here’s how” achieves the same capability in about 200 tokens. That’s a difference of two orders of magnitude — the widely-quoted “250x” figure comes from exactly this comparison — and it’s paid before the task even starts, on every session, whether or not the task touches GitHub at all. Chinese developer communities circulate broader claims — 10-32x per-call cost multipliers, 72% task reliability for MCP versus near-perfect for CLI — which I haven’t been able to trace to a reproducible benchmark, so treat those as folklore. But you don’t need folklore. The token math on the GitHub case alone is verifiable, and it’s damning.
The context cost has a second-order effect that’s worse than the bill: it degrades the model. Every thousand tokens of schema is a thousand tokens the model can’t spend on your actual problem, and tool-selection accuracy measurably drops as the tool list grows. I explored this dynamic in my context engineering deep dive — attention is the scarce resource, and MCP’s design spends it on plumbing. CLI has structural answers MCP lacks: output can be piped through jq or grep so only the relevant slice ever reaches the context window; errors are plain text the model has seen before; debugging means copying the exact command into your own terminal. With an MCP failure, you can’t easily reproduce what the agent did. With a CLI failure, the reproduction is the command itself.
Skills Are the Layer That Actually Replaced MCP
Here’s the subtlety the “CLI vs MCP” framing misses: raw CLI access alone didn’t dethrone MCP. What dethroned it was CLI plus a knowledge layer — the SKILL.md file. A skill is a Markdown document that encodes a workflow: which commands to run, in what order, what the edge cases are, when to stop and ask. It’s a standard operating procedure written for a reader that happens to be a model. I made the case in Agent Skills: Why Markdown Files Are the New Programs that this is a genuine programming paradigm; six months later I’d sharpen it: Skills replaced the orchestration value of MCP, and CLI replaced its execution value. Between those two, there was nothing left for MCP to do in the common case.
I run this architecture in production, and it’s not a toy. My daily driver is a set of 27 skills wrapping lark-cli, the official Feishu/Lark command-line tool I covered in my Lark CLI guide — messaging, docs, spreadsheets, calendar, approvals, video-conference records, each one a SKILL.md that names the CLI subcommands, shows canonical invocations, and documents the identity/permission gotchas. Total resident MCP servers required: zero. When I ask my agent to “pull yesterday’s meeting notes and message the summary to the team,” it reads two Markdown files (~a few hundred tokens each, loaded only when triggered), runs four CLI commands, and done. The equivalent MCP topology would be two resident servers, tens of thousands of schema tokens, and two more processes that can be down when I need them. The blog itself runs the same way — the cover-image skill from failure two is now a SKILL.md orchestrating a direct-API Python script.
The strongest external validation of this pattern comes from CompanyOS, which is instructive precisely because it kept its MCP servers. The system connects 8 MCP servers for Gmail, Linear, and Help Scout — but its builder is explicit that the soul of the system is 12 skill files totaling about 2,000 lines of Markdown encoding workflows, guardrails, tone, and decision logic. The MCP servers are plumbing; the skills are the asset. Changing behavior means editing Markdown and committing — a feedback loop of minutes, reviewable by teammates who can’t read the server’s implementation language. That division of labor — intelligence in Markdown, transport wherever convenient — is the actual end state, and it demotes MCP from “the integration” to “one of several interchangeable pipes.”
There is one honest cost, and I want to state it plainly rather than bury it: a text SOP is not code, and it will not execute with 100% determinism. A model can misread a step, skip a guardrail, or improvise where you wanted compliance. My mitigation, learned the hard way: anything that must be exact goes into a script the skill calls; the skill’s prose handles only the judgment calls. Skills for decisions, scripts for precision. If a workflow can tolerate zero deviation and involves no judgment, it shouldn’t be a skill at all — it should be a cron job, which is exactly where my Search Console pipeline ended up.
flowchart TB
subgraph SKILL["Skill layer — the SOP (what and when)"]
S1["SKILL.md files
workflow steps, guardrails, edge cases
~200 tokens, loaded on demand, git-versioned"]
end
subgraph EXEC["Execution layer — the hands (how)"]
C1["CLI tools
gh, aws, lark-cli..."]
C2["Scripts
direct API calls, cron jobs"]
end
subgraph MCPN["MCP layer — the remaining niche"]
M1["Dynamic tool discovery
C-end products, changing tool pools"]
M2["OAuth-managed remote services
no local credentials"]
M3["No-shell sandboxes
web-based agents"]
end
S1 -->|"orchestrates"| C1
S1 -->|"calls for precision"| C2
S1 -.->|"only when no CLI/API path exists"| M1
S1 -.-> M2
S1 -.-> M3
style SKILL fill:#1a5276,stroke:#5dade2,color:#eaf2f8
style EXEC fill:#145a32,stroke:#58d68d,color:#eafaf1
style MCPN fill:#6e2c00,stroke:#eb984e,color:#fdf2e9
The Honest Case for MCP: Where It Still Wins
Most of the “MCP is dead” posts fail their own credibility test by never steelmanning the other side, so let me do it properly — because I still run MCP servers for specific jobs, and the reasons are structural, not sentimental.
No shell, no CLI argument. Everything above assumes your agent has a shell. Web-based agents, mobile assistants, and locked-down enterprise sandboxes often don’t, and for them the entire CLI thesis evaporates. MCP’s transport works over HTTP into environments where “just run gh” is not a sentence that means anything. This is not a small market — it’s most consumer AI products.
Dynamic discovery is real value when the tool pool actually changes. My lark skills work because Feishu’s command surface is stable. A consumer agent facing an open-ended ecosystem — where users connect their own third-party services at runtime — genuinely needs runtime discovery, and a protocol with schemas beats a folder of Markdown for that. The mistake of 2025 wasn’t building MCP; it was defaulting to a dynamic-discovery protocol for static toolsets, paying flexibility costs for flexibility nobody used.
Managed auth and audit boundaries. When my puppeteer script connects to my logged-in Chrome, it inherits my full session — convenient, and exactly the kind of ambient authority that makes security teams sweat. A remote MCP server with hosted OAuth gives an enterprise a chokepoint: scoped tokens, revocation, an audit log of every call. And be honest about the flip side of the CLI thesis: handing an agent a shell hands it arbitrary command execution. I wrote about this tension in my MCP security guide — a constrained protocol surface is a feature when the threat model includes prompt injection. Cross-platform consistency cuts the same way; my skills quietly assume macOS and would need real work on Windows, while a protocol schema doesn’t care.
Notice what all these wins have in common, though: they’re environmental — no shell, no stable tools, no acceptable local credentials. None of them is “MCP integrates better when a CLI exists and works.” That’s why I call this a demotion rather than a death: MCP keeps the territories defined by constraints, and loses everywhere developers have a choice.
Convergence, Not Funeral: The Layered End State
So where does this settle? The most credible preview came from Microsoft, of all places. Their .NET Skills Executor is a hybrid: SKILL.md files discovered from a directory drive the agentic loop, and MCP servers sit underneath as one execution backend among several, invoked silently when a skill’s step needs them. The intelligence lives in Markdown; the protocol is demoted to plumbing that the skill author chooses per step. Microsoft simultaneously ships official skills repositories grounding coding agents in Markdown. When the company that operationalizes every enterprise standard puts skills on top and MCP underneath, that’s the org chart of the future stack: Skill as the SOP layer, CLI/script as the default execution layer, MCP as a fallback transport for the cases the first two can’t reach.
This resolves the false binary in most “is MCP dead” takes. The question was never protocol versus no protocol; it was which layer owns the knowledge. In 2025 we tried to put workflow knowledge into tool schemas — that’s what those 50K-token definitions were, badly compressed SOPs — and it failed because schemas are a terrible medium for judgment. The knowledge moved into Markdown, where it’s cheap, versionable, and readable by both models and humans. Once that happened, the transport underneath became a commodity, and commodities get selected on cost. CLI is the cheapest transport that exists, because the model already speaks it. My earlier Skills vs MCP comparison treated the two as complementary peers; six months of production later, I’m revising that: complementary yes, peers no. One is the trunk, the other is a branch.
A Migration Framework You Can Run This Week
Enough thesis. Here’s the decision procedure I actually used to migrate my own stack, formulated as signals. Audit each MCP server you run against these five:
- A CLI or scriptable API already exists for the service (
gh,aws,kubectl,lark-cli, an official REST API with token auth). The MCP server is a translation layer over something your agent could touch directly. - Your agent has shell access. If yes, the CLI thesis applies in full.
- The workflow is repeatable. You call the same 3-5 tools in similar sequences. You’re paying dynamic-discovery prices for a static routine.
- Schema cost dwarfs usage. The server loads thousands of tokens of definitions and you use a fifth of its tools. Check your session logs — this one is measurable.
- The server needs babysitting. Auth re-configuration, resident process management, “have you tried toggling it off and on” — Garry Tan’s entire complaint list.
Three or more signals: write the SKILL.md, point it at the CLI, disconnect the server, and measure tokens-per-task before and after. The SKILL.md itself needs only four sections — which tool, canonical command examples with real output, failure modes and recovery, and hard boundaries the agent must not cross. Mine average under a hundred lines.
flowchart TD
A["Audit an MCP server in your stack"] --> B{"Does an official CLI
or scriptable API exist?"}
B -->|No| K1["Keep MCP
it IS the integration"]
B -->|Yes| C{"Does your agent
have shell access?"}
C -->|No| K2["Keep MCP
no-shell sandbox niche"]
C -->|Yes| D{"Is the workflow repeatable
same tools, similar sequence?"}
D -->|"No — open-ended tool pool"| K3["Keep MCP
dynamic discovery earns its cost"]
D -->|Yes| E{"Need hosted OAuth or
protocol-level audit trail?"}
E -->|Yes| H["Hybrid: SKILL.md on top,
MCP as silent backend
(Microsoft executor pattern)"]
E -->|No| M["Migrate: SKILL.md + CLI
disconnect the server,
measure tokens per task"]
style M fill:#145a32,stroke:#58d68d,color:#eafaf1
style H fill:#1a5276,stroke:#5dade2,color:#eaf2f8
style K1 fill:#6e2c00,stroke:#eb984e,color:#fdf2e9
style K2 fill:#6e2c00,stroke:#eb984e,color:#fdf2e9
style K3 fill:#6e2c00,stroke:#eb984e,color:#fdf2e9
One warning from my own migration: don’t skip the “measure” step. The token drop is the headline, but the number that actually changed my behavior was failure recovery time. When the puppeteer script breaks, I paste the command and see the error. When the MCP path broke, I was reading someone else’s server logs. Debuggability is the compounding return here, and it never shows up in the token bill.
My bottom line, stated as a falsifiable position: by the end of 2026, the default answer to “how do I connect my agent to X” will be “is there a CLI for X?” — and MCP will be the answer only when that question returns no. If you’re starting a new agent project today, start with skills and CLI, and add an MCP server the day you hit one of the four environmental constraints above. Not before.
Related Reading
- Skills vs MCP in Claude Code: Two Ways to Extend AI Capabilities
- MCP vs Skills vs Hooks in Claude Code: Which Extension Do You Need?
- Agent Skills: Why Markdown Files Are the New Programs
- Lark CLI Complete Guide: Control Feishu with Terminal and AI Agents
- Chrome DevTools MCP Setup: Fix “Opens New Window” + Port 9222
- MCP Protocol Explained: The Universal Standard for AI Integration
- Context Engineering for Coding Agents 2026: What Works
Comments
Join the discussion — requires a GitHub account