
This week I caught myself explaining my own architecture wrong. Out loud. With confidence.
I was describing how Repo Recommender works and heard myself say it “calls GitHub through a CLI.” I also half-remembered where my MCP server lived - was it part of Repo Recommender, or the RepoRadar project it grew out of? If you cannot answer that about apps you built three weeks ago, you have two options: guess harder, or go read the code.
I did the third thing: I asked Claude Code to read the code and tell me the straight truth. Two subagents audited both repos in parallel, then probed the live endpoints. It came back with file-and-line receipts, and it corrected me on three things I believed.
#What I had wrong
There is no CLI anywhere in the chain. Both apps talk to GitHub the same way: server-side HTTPS calls to api.github.com. RepoRadar uses Octokit, GitHub’s official SDK - with one deliberate raw fetch for search, because Octokit’s throttling plugin will happily sleep through a rate-limit window longer than a Cloudflare Worker is allowed to live. Repo Recommender skips the SDK entirely and hand-rolls fetch with the proper headers. A CLI like gh would just be a third way to make the same REST calls, from a shell, for a human. My apps never needed one.
The MCP server is Repo Recommender’s, and it is live at reporecommender.com/mcp. The design I had actually shipped is the one I would recommend to anyone: one engine, two surfaces. The same recommend() function serves the human web UI and a typed MCP tool, recommend_repos(repoOrUrl, goal), running on a Durable Object with the official MCP SDK - Streamable HTTP at /mcp, SSE fallback at /sse. Claude Code did a live protocol handshake against it mid-audit and listed the tool schema back to me.
I shipped a second MCP server and forgot it existed. RepoRadar has its own - rank_repos plus a deploy_variant tool that deploys a live micro-app - sitting on a separate worker, healthy, answering handshakes. I built it during the hackathon push and it fell straight out of my memory. The audit also flagged a trap I would have walked into: reporadar.app exists and is someone else’s product entirely. Mine is reporadar.io.
#The mental model that survives contact with the code
My old shorthand was “a CLI is one request at a time, MCP can ask for a bunch of results.” That is wrong. Both are call in, result out. The real difference is what kind of plug each one is:

The direction metaphor is the part I keep now. Southbound, your app consumes other people’s APIs - REST calls, an SDK, sometimes a CLI wrapping the same endpoints. Northbound, your app serves agents - and MCP is the standard socket for that. Implement it once and every agent client can plug in: Claude Code, Claude on the web, Codex, Cursor. USB-C for tools.
Rule of thumb: consume mature developer tools through their CLI - git and gh are token-efficient and every model has trained on them. Expose your own services to agents through MCP - typed, discoverable, permissioned per tool.
Want to feel the northbound side from the client seat? My server is public:
claude mcp add --transport http reporecommender https://reporecommender.com/mcp
Then ask Claude Code to find you an auth solution, or background jobs, or whatever your repo is missing - and watch it call my Worker as a typed tool.
#The part I keep thinking about
The agent that audited my architecture is the same kind of agent that built it. Earlier this week I wrote about building Repo Recommender the disciplined way - plan mode, CLAUDE.md, rules enforced by tooling. This is the other half of that discipline: when your memory of the system drifts from the system, do not negotiate between them from the couch. Send the agent to read the code. Mine came back in about ninety seconds with receipts, three corrections, and a feature I had shipped and forgotten.
If you cannot articulate your own architecture, that is not a character flaw. It is a prompt.