{"slug": "the-same-ai-build-went-from-30-minutes-to-4-here-s-what-we-changed-in-our-mcp", "title": "The same AI build went from 30 minutes to 4 — here's what we changed in our MCP server", "summary": "Neleto, a CMS developer, cut the time to build a landing page via its native MCP server from 30 minutes to 4 by fixing protocol-level inefficiencies. The team found that uploading images as base64 text forced the AI model to generate thousands of tokens, and that verbose API responses echoed unnecessary data. By allowing inline image ingestion and adding a quiet response mode, they reduced token usage from ~225,000 to ~40,000 and eliminated the image phase entirely.", "body_md": "We build a lot of sites by prompt. It's the whole point of shipping a CMS with a [native MCP server](https://neleto.io/docs/developer/mcp): you point Claude at a finished HTML page, and it comes back as a component-driven site with every headline, link and image editable.\n\nSo we did what you should always do with your own product — we sat down and timed it.\n\nOur original build recipe took around **30 minutes** for a single landing page. We rewrote it, cut the redundant steps, and got that to **14 minutes**. Good progress. But then we looked at where those 14 minutes actually went, and the answer was uncomfortable.\n\nThe site itself — fifteen components, a layout, a page, all wired up — took **3 minutes 40 seconds.** The remaining ten minutes were five images. Fourteen kilobytes of them.\n\nFive small images cost nearly three times more than the entire rest of the site. That's not a slow step you optimise. That's a design flaw, and no amount of prompt tuning was going to fix it — it had to be fixed in the server.\n\nThe obvious theory is network or storage. It was neither — it was the AI.\n\nWhen an agent uploads a file through a tool call, the bytes travel as base64 text — and that text has to be *generated by the model, token by token*. A 5 KB image becomes roughly 7,000 characters the model has to type out, one piece at a time. The CMS wasn't slow. The upload was slow because a language model was laboriously spelling out a picture.\n\nIt was also fragile in a way that's genuinely hard to debug. One of our test files failed twice with a padding error. The cause turned out to be a long run of repeated characters inside the base64 getting collapsed somewhere in transit — the server received 1,621 characters where 1,624 were sent. It doesn't fail loudly at the transport layer; it shows up much later as a corrupt-file error that points you at entirely the wrong problem.\n\nThe second issue was quieter but bigger in aggregate: **our API was too chatty.** Every write returned the full saved record. Save a page with eleven elements and you got back every element's complete component definition — template, CSS, JavaScript, form schema — repeated once per element. That's about 55 KB of JSON echoing back content the caller had just sent. Multiply across a whole build and the majority of the token cost wasn't instructions. It was us talking to ourselves.\n\nTwo changes, both at the protocol level.\n\n**1. Images can now be ingested inline.** Instead of uploading a file and then wiring its ID into your content, you put the URL directly in the element data:\n\n```\n\"data\": {\n  \"image\": { \"sourceUrl\": \"https://example.com/studio.jpg\" }\n}\n```\n\nThe server fetches it, stores it, and substitutes the real file ID — inside the same save, on the same transaction. No base64. No separate upload step. The bytes never pass through the model at all.\n\n**2. Responses can be quiet.** Every write tool now takes an optional `verbose: false`:\n\n```\n{ \"id\": 53 }\n```\n\nThat's the whole response now, instead of three kilobytes. For pages and layouts you still get back the element ID mapping — the one thing the caller genuinely can't work out for itself — and nothing else. It defaults to `true`, so nothing breaks for anyone already calling it.\n\nSame page, same components, same five images, three points in the journey:\n\n|  | Original recipe | Rewritten recipe | After the server changes | \n|---|---|---|---|\n| Full build with images | ~30 min | ~14 min | **4 min 0 s** | \n| Image phase | ~10 min | 10 min 25 s | **0 s** — folded into the page save | \n| Tokens | — | ~225,000 | **~40,000** | \n| Tool calls | — | 21 + uploads | **19** | \n\nWorth separating those two jumps honestly, because they're different kinds of work.\n\nGetting from 30 to 14 minutes was **prompt engineering** — fewer redundant calls, better use of defaults, dropping steps that existed out of superstition. Useful, but we'd taken it about as far as it went.\n\nGetting from 14 to 4 was **protocol work**, and it's the bigger result: roughly **3.5× faster and 6× cheaper** on an identical build. The saving comes from deleting a phase rather than speeding one up. Because a page can now be created *with* its elements *and* resolve image URLs in one call, the sequence went from \"create empty page → upload five files → write everything back\" to a single save.\n\nWhich is the general lesson for anyone building agent tooling: once you've tidied the prompt, the remaining cost is almost always in the API's shape, not the agent's instructions.\n\n**Your agent runs cost less.** Token usage on a standard page build dropped by roughly 85%. If you're running builds repeatedly — client sites, templates, a course, a test suite — that's the difference between an experiment and something you do routinely.\n\n**There's one less way to break your content.** Our element data is replace-semantics: send a partial update and the omitted values are cleared. The old image workflow forced a second write pass over content you'd already saved, which is exactly the situation where that bites. We managed to blank an entire page's text this way during testing — every section still rendered, just empty. With inline ingest there is no second pass, so the trap is gone. (It's the same class of silent failure we built [self-verifying checks](https://neleto.io/blog/self-verifying-ai) to catch — deleting the failure mode outright is even better than catching it.)\n\n**It composes with everything else.** `sourceUrl` accepts any URL the server can reach: a client's existing media library, a CDN, a generated image, or a file already in Neleto. For an agency migrating a site, that means images can move over in the same call that creates the page.\n\nA few edges worth knowing before you hit them.\n\nInline ingest needs a URL the *server* can reach. If your images only exist on your laptop, you still need to get them somewhere hosted first — the base64 path still exists for small files, and it's fine at a few KB. It's large payloads where it falls apart.\n\nThere's also a rough edge we found in our own API while testing this: a file's `serveUrl` returns a 400 if you fetch it bare, without a scaling query string appended. Which means the most obvious thing you'd try — ingesting from a file already in your Neleto media library — fails unless you add `?options=w_800,f_webp`. We're fixing it. Until then, append the options.\n\nAnd one lesson that isn't about images at all. The inline ingest worked the instant it deployed, because element data is free-form — no contract change. The `verbose` flag needed a schema change, and schemas are negotiated once when a client connects, so it stayed invisible to our own editor until we reconnected. If you build MCP tooling: behaviour-level changes reach agents immediately, schema-level ones need a client round-trip. Plan your rollouts accordingly.\n\nBoth changes are live. If you're already connected to the Neleto MCP server, inline ingest works right now — put a URL where a file ID goes. For `verbose`, reconnect your client so it picks up the updated schema.\n\nIf you haven't built a site by prompt yet, this is a decent moment. The slowest, most fragile part of the workflow just stopped existing.\n\n**Try it yourself:** [start a free Neleto project](https://neleto.io/pricing), point an agent at it, and drop an image URL straight into the element data — watch the whole upload phase disappear. [That's what a native MCP server is for](https://neleto.io/features), and if you want the deep dive on how it works, [we wrote one](https://neleto.io/blog/mcp-server-explained).\n\n**Fast websites. Easy content. AI native.**", "url": "https://wpnews.pro/news/the-same-ai-build-went-from-30-minutes-to-4-here-s-what-we-changed-in-our-mcp", "canonical_source": "https://dev.to/neletomartin/the-same-ai-build-went-from-30-minutes-to-4-heres-what-we-changed-in-our-mcp-server-2l8e", "published_at": "2026-09-08 08:00:00+00:00", "updated_at": "2026-09-08 08:31:32.185332+00:00", "lang": "en", "topics": ["developer-tools", "ai-tools", "ai-agents", "mlops"], "entities": ["Neleto", "Claude"], "alternates": {"html": "https://wpnews.pro/news/the-same-ai-build-went-from-30-minutes-to-4-here-s-what-we-changed-in-our-mcp", "markdown": "https://wpnews.pro/news/the-same-ai-build-went-from-30-minutes-to-4-here-s-what-we-changed-in-our-mcp.md", "text": "https://wpnews.pro/news/the-same-ai-build-went-from-30-minutes-to-4-here-s-what-we-changed-in-our-mcp.txt", "jsonld": "https://wpnews.pro/news/the-same-ai-build-went-from-30-minutes-to-4-here-s-what-we-changed-in-our-mcp.jsonld"}}