Workloft
▸ WORKLOFT RESEARCH NOTE №69 · 08 AUGUST 2026

The MCP Wrapper Was Never the Hard Part

A deterministic tool turned recorded API traffic into a working MCP server, with no model in the loop. We ran it end to end. The bottleneck is not the code, it is the coverage.

HANDS-ON ●●● · 8 CALLS → 5 ENDPOINTS → MCP SERVER · 0 LLM CALLS

§1The verdict: the boring bit is deterministic

To let an agent call an API you have never wrapped, someone has to describe every endpoint: the paths, the parameters, the shape of what comes back. It is the least glamorous job in agent building, and the reflex now is to hand it to a model. Point an LLM at some responses, ask for a schema, get a wrapper. It works, it costs tokens, and it quietly invents fields that were never on the wire.

There is a better way to do this exact step, and it does not use a model at all. We tested a small tool called agentspec that watches real HTTP traffic and emits an OpenAPI 3.1 spec plus a standalone MCP server, fully deterministically. We ran the whole pipeline end to end and drove the result as a live agent tool. It works. The interesting part is not that it works. It is what it exposes about where the real difficulty sits.

§2What we actually ran

We recorded eight real HTTP calls against a public test API (JSONPlaceholder, a stable sandbox built for exactly this), saved them as a HAR file, and fed the HAR in. No hand-editing. Out came an OpenAPI 3.1 spec describing five endpoints, then a 183-line Python MCP server exposing five typed tools.

Then the real test: we started that generated server and drove it as an MCP client, the same way one of our agents would. It listed its five tools with correct input schemas, and live calls came back with real data. Ask for post id=1 and you get the post. Ask for user id=2 and you get the user, nested address and all. At no point in capture, spec generation, or server generation did a single model token get spent. The one place a model belongs is the very end: the agent deciding which of these five tools to call, which is the part a model is actually good at.

§3Deterministic means it only ever claims what it saw

The reason to prefer observation over inference here is not purity, it is trust. Watch what the tool did with the traffic. It saw /posts/1 and /posts/2 and collapsed them into a single /posts/{id} with a templated path parameter. It saw /comments?postId=1 and modelled postId as a query parameter, not part of the path. It noticed the same response shapes recurring and hoisted them into shared schema components, including a nested address object living inside the user record.

Every field in that spec is a field it observed on a real response. Nothing is guessed. That is the property you want in a wrapper an agent will call without a human watching. An LLM asked to do the same job will, on a thin sample, help you out by adding the fields it assumes an API like this "should" have. That is the failure you cannot see until an agent calls a parameter that does not exist. Deterministic generation cannot do you that particular favour, which is the point.

§4The catch: coverage, not code

Here is the honest part, and it is the whole reason this Note exists. Every one of our five endpoints came back tagged low confidence. That is not a defect, it is the tool refusing to oversell. It had one or two samples per endpoint, and it says so, per endpoint, in a confidence report. A schema learned from two examples is a schema that breaks the first time a field it never saw turns up. If every call you captured for POST /posts happened to include a title, the tool has no way to know title is optional. It can only describe the traffic you gave it.

So the difficulty does not disappear, it moves. It stops being "who writes the wrapper" and becomes "did your traffic actually exercise the API". The empty list, the second page, the 404, the request that omits the optional field: if your captured traffic never hit those, the spec will be confident and narrow, which is the worst combination. The work shifts from typing out the wrapper to getting representative coverage. That is a better problem to have, because coverage is a testing discipline you already understand, but it is still a problem, and no code generator removes it.

§5Where this earns its place, and the caveat

For us the win is the boring eighty per cent. Any API with no usable spec, an internal service, a third party whose docs lie, a legacy endpoint nobody documented, can become fleet-callable from captured traffic in minutes instead of an afternoon of hand-writing. The confidence report doubles as a to-do list: it tells you precisely which endpoints are under-sampled, so you know exactly what traffic to go and capture next. We would treat the generated spec as a strong first draft, widen it with more traffic, and eyeball it before letting an agent call anything that writes.

The caveat, stated plainly: we tested read-heavy, idempotent calls against a public sandbox with no authentication. Point this at a real API behind real auth, with real write methods, and two things we did not lean on start to matter a great deal: how the tool handles credentials, and its replay probes for telling a genuinely public endpoint from one that only looked public because your session cookie rode along. That is a separate test, and we have not run it yet. What we can say from this one is narrow and true. The wrapper was never the hard part. Getting the traffic to describe the whole API still is. Credit to agentspec by Hugh White for building the deterministic half well enough that the remaining problem is the honest one.


Methodology note. Run on 08 August 2026 against agentspec 0.3.1 (PyPI), installed in a clean virtualenv with the generate and yaml extras. We recorded 8 real HTTP calls to jsonplaceholder.typicode.com (6 GET, 2 POST, statuses 200/201) and serialised them into a HAR 1.2 file. Command path: agentspec capture --har produced an OpenAPI 3.1 spec (5 endpoints, 4 hoisted component schemas); agentspec generate mcp produced a 183-line stdio MCP server. We then connected to that server with a standard MCP client, enumerated its 5 tools, and made live tool calls that returned real payloads. Zero LLM calls at any stage of capture or generation, verified by the tool's own design (no model dependency) and by the absence of any API key requirement. All five endpoints were self-reported as low confidence (1 to 2 samples each); that signal is the subject of §4. Caveat: read-heavy, unauthenticated sandbox only; auth handling and write-method probing were not exercised.