Bryan Thompson

MCP Infrastructure Engineer, Anthropic

I build the pipelines that get plugins to Claude users.

Two of them: the Claude plugin directory and the MCPB desktop-extension pipeline. Build, audit, publish — across six source ecosystems, with drift detection running daily over thousands of listings.

The public trace

Most of this work happens in public repositories, so you don’t have to take my word for any of it. Every number below links to a live GitHub search that recomputes when you open it.

The 350+ are mine. Most are catalog operations, a good share of them emitted by the same automation — and in among them are the changes that built it, which you can read: the bump loop and the recovery job that catches it. The 5,000+ are submissions and rolling updates moving through that automation: each one scanned, validated, and policy-checked before it reaches a merge decision. Building the system was the work; the volume is what it produced.

† The modelcontextprotocol/mcpb row is open-source maintenance — issue and pull request threads participated in — not pipeline throughput, and it is not included in the throughput total. Every figure above is a floor, not an estimate: these counts only grow, and the totals moved by several hundred in the days it took to write this page. Floors verified against the GitHub API on 2026-08-10, and re-checked in CI; each links to a live search that recomputes the exact number when you open it.

Before this: a career in reliability engineering on Fortune 500 payment systems at PayPal and Fiserv. That’s where the instinct for staged rollouts and blast-radius containment comes from.

An instruction in an agent's context is not a control surface

I move agent work onto boundaries a machine can check, measure the boundaries instead of asserting them, and fix by rule rather than by trust what one agent may conclude from another's report. Each page below names what its boundary still does not cover, and each hands you a line you can paste into a Python REPL or a browser console.

A skipped step leaves a gap you can query for, not silence

if not s.strip(): allow() is the obviously correct short-circuit at the top of a gate that runs before an agent emits text a human will act on, and it is deliberately absent from mine: a gate written in one language guarding a sender written in another inherits every disagreement between their standard libraries. A body of nothing but U+001C–U+001F and U+0085 is length 0 to Python's strip(), which allows it, and length 5 to JavaScript's trim(), which sends it. A corrective rule had been loaded into context and the steps it governed were skipped anyway — so the load-bearing ones came out of prose and onto boundaries a machine can see.

Read the method →

The crude attack failed and the polite one worked

A black-box harness I built drives a real agent runtime against fixtures I control and scores what happened rather than reasoning from the spec. Almost every such measurement reports an absence — which is also what a broken instrument reports for free — so what publishes is the instrument discipline: positive controls on the same capture surface, and “I failed to observe” kept separate from “I observed a failure”. The fixtures move one variable at a time, which you can check in a line: the four-character matcher returns no term at all for a positional tool name, and two for a descriptive one. The one result that ships: in those fixtures an instruction shaped like ordinary documentation was followed by one model where a blatant override was refused by both. No rate is attached, because a fraction a reader cannot re-derive is not evidence.

Read how it was measured →

A message can say where to look, never what is concluded

Between agent sessions I let a message select what to verify, and never let it supply what is concluded. One stock-Python line shows why the obvious if "\n" in msg: reject() anti-forgery filter is not enough: a message carrying U+2028 contains no newline and is nonetheless two lines to splitlines(), so its second line can begin with the renderer's own output prefix and arrive as a forged record. Every layer that can act on a message stays deterministic, and a differential test proves that rather than asserting it. The parts that are still only convention — which session may merge, which may only read — are named on the page as unenforced, because no hook or permission profile checks the caller.

Read what it does not enforce →