Connecting Private Systems to Claude: What I Learned Building an MCP Gateway
I wanted to find out whether our internal, VPN-only systems could be made usable from Claude, with real identity, and without the connection turning into a

A web agency takes its clients from idea to finished website along the same path it used twenty years ago: a briefing becomes a concept, the concept becomes a design, the design goes to the client for sign-off, the sign-off becomes a handoff to engineering, and the handoff becomes the finished site. That chain has not survived out of inertia. It holds because every station has a purpose, and sign-off sits exactly where clients need it.
What has changed is the material running through it. A design used to be an image, built in Photoshop, read by eye. Today Figma delivers a structure of components, instances, and tokens, and at the end of the chain sits a content management system like TYPO3 instead of hand-written HTML. Where pixels used to sit, something machine-readable sits now, and that turns an old question into a new one with three possible answers instead of two: which part of this chain still needs a human to carry it? Which part needs a model that can reason, because there is something to interpret? And which part can be pinned down precisely enough to run deterministically?
This comes out of a live agency project: a Claude Code harness reads a signed-off Figma design, checks it against a versioned design contract, and generates TYPO3 Content Blocks and pages the editorial team can fill.
Most of it is translation work that repeats itself. The same slider pattern, the same navigation scheme, the same card component migrate from Figma into a content structure, project after project. What gets lost is not the structure, that reads out cleanly on both sides. What gets lost is the intent behind it: whether a slider is built to hold any number of elements or fixed at a set count, where a menu item is actually supposed to link, whether a decorative element with no text is meant to be a real toggle. That intent lives in the rich channel of conversation between design and engineering, not in the lean channel of a file, and that gap is what media richness theory has described since the 1980s1.

Anyone promising to automate exactly that step reaches for a catchy image: a "dark factory" running from Figma to a finished page with nobody watching. Even where the engineering holds up, a structural problem remains: the organization around it is not built for a machine to guess where a human used to ask a question.
So the question that matters is not whether AI makes this process cheaper. It is whether AI makes it better. The answer we have been building toward for months, in a live client project: don't automate people out of the process, formalize the handoff that used to run on conversations and briefings. Implicit design intent becomes a written, versioned contract between design and build, using thinking tools borrowed from Domain-Driven Design and Team Topologies. A Claude Code harness reads that contract and carries the Figma design through a largely deterministic process into TYPO3 Content Blocks. Probabilistic reasoning stays exactly where something genuinely needs interpreting, nowhere else. The boundary between these parts is not fixed: once something is negotiated and written down, it stops being an interpretation and becomes a rule you can check.
The lever behind it is a split. Work on the technical foundation and reusable components enriches a library and pays into every future run. Work on content, assets, and polish stays local to a page and does not accumulate. That split is not specific to Figma-to-TYPO3. It generalizes to any existing, human-heavy process you want to improve with AI instead of merely speeding up.
Before you automate a process, you have to know it well enough to see where it gets complex. At a design agency, the path from idea to website runs through five roles: clients who brief and sign off, project leads who translate between client and engineering, designers working in Figma, backend engineers who deploy TYPO3 and build the structural Content Blocks, and frontend engineers who do the fine work in HTML, CSS, and JavaScript. Sign-offs happen in conversation, not through a document.
The handoff this piece is about sits between the two middle roles: what the design side means in Figma has to become a content model that backend engineering builds in TYPO3. Today that translation is carried by the project lead, in conversation, from experience. It works as long as the same people keep working together, and it is exactly the point where a machine would have to guess without an additional agreement in place.
Inside that chain there is one edge we deliberately did not automate. Project leads and designers iterate with the client until a concept is signed off, and what comes out of that condenses into a Figma file. The input contract for everything after that is exactly that: a signed-off Figma file. Everything before it is human terrain, a rich channel of conversation and compromise. That channel is not irreplaceable because of how much information flows through it, but because that is where decisions get made about things there is nothing to look up1. Whether a given frame is the navigation or an ordinary section is not written anywhere; someone settles it. What comes out of that settling can be captured, though, and that is exactly what the contract targets: not the negotiation itself, but what it produced. Everything after that is where the factory takes over, and whether the target is TYPO3 or WordPress barely changes it: both are the destination of the same translation chain, just with a different content model behind them.

The obvious first instinct is to automate this as completely as possible: Figma file in, finished website out, no human in between. We deliberately did not chase that instinct, and the reason sits in the input, not the technology. At several points in the chain, something has to be settled that the Figma file alone cannot answer, say, whether a slider carries exactly three elements because that is the rule, or because three happened to be drawn. A model with reasoning gets far on questions like this, but only as far as an answer actually exists. One kind of question has an answer: it sits in the designer's head, a fact that simply never made it into the file. The other kind has no answer anywhere, because nobody has made the decision yet.
Full automation does not resolve these points. It moves them into the machine and pushes them to the end of the run, where they only surface in the finished screenshot. Fixing them there costs an entire build instead of a minute, and a client project rarely forgives that.
So the factory stops deliberately at these points, before a single line of TYPO3 code gets written, and what happens after the stop depends entirely on that distinction. If a fact is missing, the run aborts and the information gets added where it belongs. If a decision is missing, the factory writes down a proposal that a person confirms or corrects. Each case gets its own discipline.
The assumption we started with: most of the avoidable uncertainty sits at a single boundary, the implicit design intent that used to form, and stay, in the conversation between design and engineering. Turn that boundary into a contract that spells out what follows from Figma and what a human has to decide once, explicitly, and the run afterward becomes controllable: whatever uncertainty remains surfaces at named checkpoints, instead of only in the finished result. That is the core of a dark factory in this sense: not a system that runs without any human at all, but one that names precisely where a human is needed, and runs everything else in the dark.
Uncertainty does not disappear with that. It gets sorted. Several classes of open points remain: page tree and section roles, component identity, editorial completeness, brand typography, production readiness. Each one now has a named place where it shows up, and a point in time where clearing it is cheap.
We built this for a design agency that wanted to automate its website production, from Figma to TYPO3, as far as it reasonably could, for its own B2B clients. Claude Code carries the run: it reads a Figma file, derives a page structure from it, builds TYPO3 Content Blocks (a content model where every content type is described declaratively, and TYPO3 generates the database schema, field configuration, and backend forms from it, while the Fluid templates ship versioned alongside the Content Block2), and hands over a page the editorial team can fill in.
The core of this factory is not a piece of code. It is a document: the Figma structure contract. It defines how a Figma file has to be built for the factory to reliably derive a TYPO3 page from it, in numbered rules, each with a compliance level (must, should, or may) and a clear note on how it gets checked. Domain-Driven Design offers two patterns that fit here: a Published Language as a shared, documented exchange format, and an Open Host Service as a stable point of access to what the build side offers3. The Figma structure contract is the Published Language for this boundary, the shared vocabulary between a world that thinks in layers, frames, and instances, and one that thinks in content types, fields, and records. Seen through Team Topologies, the collaboration moves toward X-as-a-Service, away from constant case-by-case coordination and toward a defined interface4. Anyone who comes from API design will recognize this as nothing more than a contract, just between design and build instead of between two services.
Two disciplines keep this contract reliable, and they map onto the two stop-classes above. The first is called no-silent-drop, and it catches the case where the information simply is not there: every section, every component instance, every reference that cannot be clearly resolved while reading the Figma file becomes a named entry in its own list instead of quietly vanishing. The factory ends a run with a clear error code the moment that list is not empty, instead of passing along an incomplete result that looks like success.
An error code alone does not help a designer much, because it speaks the language of the build side. So the question travels back translated, as a concrete question at the exact spot in the Figma file, in the designer's own vocabulary, instead of as a field or content-type problem. The reasoning does the translating here, not the deciding. The contract becomes a boundary that speaks in both directions, and the work goes back to wherever it is cheapest to do.
Whether this discipline actually holds shows up in a stress test against a deliberately messy reference Figma file from an earlier phase of the project. The first loud run against that file, loud meaning here: one that flags every unresolvable element as an error instead of skipping it, found two genuinely unresolvable references that the older, quiet version of the code had swallowed without complaint. A quiet check passes against junk exactly as it passes against clean material. A loud check exposes the junk on first contact.
The second discipline is called orient-then-build. It catches the open choice, and it sits at the start of the chain instead of the end. Some decisions cannot be derived from a Figma file at all, say what the overall page tree looks like, or what role a given frame plays in the layout. Instead of guessing at these gaps late, and only discovering the error on the finished render after the build, which makes every fix expensive, the factory writes down its best guess in a first phase, as an editable, schema-checked document. A human corrects that guess once, cheaply, in a text editor. Once confirmed, the semantics are frozen: the structural build on top of it runs deterministically, and probabilistic work stays confined to the explicitly marked classification and review points.

A gap like this can also be closed for good, and that is the more interesting move. Navigation, header, and footer looked in Figma like any other section; whether a given frame was the menu or a content block was not something the file could decide. Instead of teaching the factory a smarter heuristic, we sat down with design, project leads, and engineering and asked how this case had been solved so far. The answer: in conversation, every time. The three sides worked out the rule together. Navigation, header, and footer now live in their own frame that carries exactly that meaning, and each of these elements may appear at most once per page. Everything else lives in the frame for page modules and becomes freely placeable Content Blocks.

A question that used to require a human answer every time is now a rule a machine can check. That is the point where work on the harness stops being pure engineering. Every round like this improves not just the factory, but the process before it: what used to get renegotiated in every project is now decided once, and it lives in the contract.
Before this, the handoff was freestyle: no fixed shape, no interface semantics, no document. The same blind spot existed on our side. We had already built the same pattern three times over, for the page tree, for section roles, for decorative elements, without ever naming it. Only when someone asked how those three solutions related to each other did it become visible that it had been the same thing all along.
The same discipline holds in places nobody expected it to. On one of the projects, a licensed brand font was hanging off an external delivery service instead of being self-hosted like the rest of the assets. A less careful pass would either have kept that as-is or silently replaced it with a fallback font. The factory does neither: it keeps building with a clean fallback so everything stays readable, and the automatically generated handoff report carries an explicit line at exactly that spot, stating that the licensed fonts need to be wired in before going live. Not a bug in the factory, but a production-readiness gap that a careful check surfaces instead of swallowing. One discipline, three different objects: a Figma reference, a font license, our own project methodology.
That this contract is not a document you write once and set aside shows in its own change history. The first complete factory run for a B2B client out of the agency pipeline pushed it to version 1.4, driven by findings on real material, including the mixed-up demo figure mentioned above. A later, first run for a separate B2B industrial client pushed the same contract to version 1.8, because a false ambiguity-detection showed up there that had never surfaced at the first client. New observations change the contract first, then the briefing and the review logic, never the other way around. That is the real proof that this boundary learns: a document that gets sharper with every real project, instead of staying a spec written once.
For the five roles above, that translates into something concrete. Designers get questions back in their own language, at the point in the file where they belong, instead of as a field error out of the backend. Backend engineers lose the recurring translation work and keep the cases that genuinely need a decision. Frontend engineers keep their fine work and gain something nobody used to hand them. And project leads no longer have to carry the translation between design and engineering in their head: what used to live as experience, tied to specific people, now sits in a document you can read, check, and pass on. That is the part that makes an agency less dependent on individual people, and in practice, the reason a contract like this gets defended when a project runs tight.
What the frontend side gets on top of that is the editorial edge cases. Because the factory knows the content model, it can fill the page itself with the extremes: an image that is too big, one that is missing, a field that never got entered, a two-word headline and one that runs three lines. Those are exactly the cases where a layout breaks later, and until now, they only showed up once the editorial team produced them, long after sign-off. Now they sit on the table before styling even starts. That saves the frontend side the work of hand-building test content, makes the build robust against editorial reality from the start, and gives the factory sharper material for its own comparison against the target state.
The harness is made of four kinds of building blocks, not one large script. Versioned reference knowledge and procedures, for instance how a Figma frame turns into a Content Block field. Explicit entry points a human or another process can use to trigger a concrete step: build a page, scan a component, run a contract check. Specialized subagents for the judgment-heavy work, for instance deciding whether two Figma components with the same name mean the same thing or two different things. And deterministic steps run over the CLI and PHP. In Claude Code, the first two are by now the same construct; custom commands have merged into skills. The distinction that actually matters is a different one anyway: which step is allowed to guess, and which is not. That is harness engineering in the literal sense, not a prompt that hopes for the best, but a system that defines where randomness is allowed.
An external counter-check belongs in there as a fixed part, though with a sharper justification than the one usually given. A recent study ran 48 independently generated implementations of the same specification against each other, diversified across agents, models, and programming languages, tested with a million random inputs against a shared oracle5. The versions failed together far more often than the independence assumption predicts, and those shared failures cluster exactly where the specification is ambiguous. Model diversity does not buy independence. It does not replace a precise contract; it is one more checking perspective alongside it.
That is exactly how we use it. Every spec and every plan runs additionally through Codex, a model from a different family than the one that wrote the first draft. The reason not to write this off as ritual is a finding: this second perspective found four spots, while working on the component index, where the index was silently swallowing Figma information, before the no-silent-drop discipline even existed.
How this factory talks to the two ends of its chain, Figma on one side, TYPO3 on the other, looks contradictory at first: on one side MCP, the Model Context Protocol, barely shows up; on the other, it carries the work. Behind that sits the same rule. MCP is a strong interface anywhere reasoning is actually in play: exploratory back-and-forth, clarifying detail, work on the harness itself. It sits wherever the reasoning sits.
And the flywheel systematically shrinks exactly that share. Every time an undecidable point turns into a contract rule plus structure in the Figma file, a piece of reasoning disappears from the run, and with it the need for an interface built for reasoning. That MCP barely shows up on the Figma side today is not a knock on the protocol; it is a byproduct of the deterministic ambition. An early test run used a hosted Figma MCP server for a single verification task; for production extraction, that workflow did not fit, because it depended on the current selection instead of a versioned extraction artifact. The factory now reads Figma through the regular REST interface as a committed, versioned snapshot, plus a self-written Figma plugin, roughly eighty lines long, that exports design tokens like colors and spacing. Reproducible, versioned, no risk of hitting a rate limit mid-run.
On the TYPO3 side, a genuine dialogue mode remains: a person fills fields, adjusts, asks follow-up questions. MCP is accordingly a load-bearing, verified part of the factory there: a community-maintained TYPO3 MCP server (hn/typo3-mcp-server) that Claude Code talks to over a local connection. Every write goes through TYPO3's own DataHandler into a workspace draft; nothing goes live before it is explicitly published. The full path from write, through workspace and preview, to publish and frontend, has run end to end once, on a demo page with several card records. Two write paths deliberately coexist here. The deterministic build assembles an entire page from the confirmed declaration and talks directly to the DataHandler through its own PHP command. The interactive editorial loop, where individual fields get filled in or adjusted, talks to that same DataHandler through the MCP server. One safe write layer, two entry points, depending on whether a machine is building through or a human is working in dialogue.

A claim is only as good as the number behind it. And a number is only as good as what you know about its denominator.
After every build, the factory automatically compares the resulting page against the Figma reference, along several axes: content completeness, font, color, spacing, and an overall visual comparison. Across five measured runs on a live client instance, every page reached converged status within one or two passes. One page started with four open findings at this aggregated level and was down to zero after the second pass; every other page got there on the first. Every automatically applied fix had its effect confirmed by the following check, in every one of the five runs.
Anyone coming from the AI side will recognize the role evals usually play here. The difference sits in the ground truth. An eval set is hand-curated, small, and expensive, so you measure in samples and at specific points in time. Here the reference falls out as a byproduct: the signed-off Figma file is the target state, it already sits versioned in the repo, and nobody has to label it. So instead of sampling, every element on every page gets checked on every run. What accumulates there sits one level below the four findings mentioned above: individual check points per axis rather than aggregated convergence findings, and the two levels do not compare directly.
That does not make them a success metric yet. These are absolute numbers across pages of different sizes, and a check point is not the same as a flaw a person would actually notice. Findings per hundred checked elements, share of findings fixed automatically, manual interventions before sign-off: those would be the metrics comparable across projects, and we do not have them yet.
What the numbers are good for is a map. Color and spacing sat consistently low across all five runs, and the overall visual comparison, checking whether every signal laid down in the design actually lands on the page, reported zero open points in every single run. Completeness, on the other hand, reported between roughly eighty and over four hundred points per run, font between roughly twenty-five and just under a hundred fifty. Layout and color are cheap and reliable for the machine to resolve from computed values. Whether an editorial field is actually filled with real content, and whether a font really matches the brand spec, needs something closer to a checking eye than pure computation. That is exactly where human attention belongs, instead of spreading evenly over work that is already cheaply solved.
One number is deliberately missing from this picture, because the data does not support it: whether a second or third page in a project converges faster than the first, because the factory learns over time. The architecture is built exactly for that, but proving it needs more complete runs per page, across more projects, than exist today. That stays an open next step, not a claim.
I spend a lot of my other work with Wardley Maps, helping clients see what in their value chain is already commodity and can be automated, and what genuinely demands individual work. I see that same boundary again in this project, just drawn more precisely than usual: as a contract rule with a compliance level and a check behind it, instead of a rough rule of thumb. What convinces me here is not how much this factory automates. It is how precisely it names what it deliberately does not automate, and that this boundary gets adjusted against reality on every new project.
What surprised me most is how small a share color and spacing turn out to be, compared to completeness and typography. Going in, I would have guessed that pixel-perfect visual precision is the hard part of a factory like this. The convergence numbers say something different: computing is cheap, looking closely is expensive. Skip that distinction, and you end up thoroughly defending the easy problem while leaving the expensive one on the table.
What comes next is foreseeable and not yet built. The factory today runs as a single-player harness, one context carries a run from start to finish; a plausible next step is a shared version where several people work against the same instance. And turning convergence numbers into comparable measurement series runs through structured telemetry, not hand-maintained log files.
Anyone evaluating something like this for their own agency or company does not start with Claude Code or MCP. They start with three questions. Where does the most expensive implicit handoff sit in your process today, and who is carrying that knowledge in their head instead of in an artifact? What information at that boundary has to become explicit so a machine can read it without guessing? And which decisions can stay probabilistic afterward, without a mistake getting expensive?
Every gap that turns up deserves a second question: is a fact missing here, or is a decision missing? Where a menu item is supposed to link is something somebody on the team knows, it just never got written down. You enter it; that needs no meeting. Whether a frame is the navigation or an ordinary section, on the other hand, nobody knows, because there is nothing to know there: several readings are valid, and someone has to decide. Daft and Lengel drew this same distinction back in 19861, and it saves you from spending effort in the wrong place. It also tells you where AI does not help: where there is nothing to know, every model guesses, no matter how many you run.
That is exactly what we work on with teams: map the process before automating anything, write the first version of the contract, and build the harness so the team can keep developing it on its own afterward.
The real turning point usually does not come with the first automation. It comes at the moment a team's own process shows up explicitly for the first time, with every point where someone used to guess quietly. That alone changes how a team thinks about its own work, regardless of how much of it ends up automated in the end.
The basis for this piece is architecture decision records and a measured convergence log from a live instance of the factory in a neighboring repository, not a secondhand summary. Claude helped me turn that raw material into an outline and a first draft, with the instruction to put the thesis first instead of building up to it at the end. Every number here, the axis values from the convergence log, the version numbers of the Figma contract, the MCP details, I checked back against the original files. Three things I deliberately do not claim, because the data does not support them: that a later page converges faster than the first one, a percentage figure for time saved, and any number in euros. Client, personal, and project names are anonymized. More on the workflow behind this: AI-Assisted Knowledge Work: How I Am Rebuilding My Research and Writing Process.
Daft, R.L., Lengel, R.H. (1986). Organizational Information Requirements, Media Richness and Structural Design. Management Science, 32(5), 554-571. ↩︎ ↩︎ ↩︎
FriendsOfTYPO3 (2026). TYPO3 Content Blocks: Documentation (main/1.x). docs.typo3.org. docs.typo3.org/p/friendsoftypo3/content-blocks/main/en-us ↩︎
Evans, E. (2003). Domain-Driven Design: Tackling Complexity in the Heart of Software. Addison-Wesley. ↩︎
Skelton, M., Pais, M. (2019). Team Topologies: Organizing Business and Technology Teams for Fast Flow. IT Revolution Press. ↩︎
Ron, J., Baudry, B., Monperrus, M. (2026). N-Version Programming with Coding Agents. KTH Royal Institute of Technology / Université de Montréal. arxiv.org/pdf/2606.20158 ↩︎
You are interested in our courses or you simply have a question that needs answering? You can contact us at anytime! We will do our best to answer all your questions.
Contact us