Schema-first discovery: unknown source, exact fields
Captured traces of the discover-before-pull switch: schema: true returns a JSON body’s shape as select-ready paths — or a markdown page’s heading outline — then a cached second call extracts exactly what’s needed.
The research question
"Where's the tarball for hono, and how big is it unpacked?" The npm registry knows — but the agent has never seen this API's shape. Every capture on this page is from 8 Aug 2026, from Claude Code; payloads verbatim.
The ordinary cost — the whole document, to learn two field names
Without a shape, discovery means pulling the full body into context just to see what exists. Here that's 19,877 bytes (~5k tokens) — measured with a capped probe; on a bigger API it's a megabyte.
// the size, measured with a capped probe fetch("https://registry.npmjs.org/hono/latest", max_bytes: 300) [via direct]{"bugs":{"url":"https://github.com/honojs/hono/issues"}, "dist":{"shasum":"d4a606b792954d07a6215d12c01b7cf59da03cbc", "tarball":"https://registry.npmjs.org/hono/-/hono-4.13.1.tgz", "fileCount":565,"integrity":"sha512-kdJoFVv2… [truncated at max_bytes=300 of 19877]
Discover the shape — for pennies
schema: true returns a compact inferred schema instead of the payload — keys spelled as select paths, leaf types, array lengths. Arrays are sampled with keys merged, so a field present in only some rows still shows.
// unknown API — ask for its shape fetch("https://registry.npmjs.org/hono/latest", schema: true) { "name": "string", "version": "string", "dist": { "tarball": "string", "unpackedSize": "number", "signatures[]": { "$items": 1, "sig": "string", "keyid": "string" } }, "maintainers[]": { "$items": 1, "name": "string", "email": "string" }, "keywords[]": "string (15 items)", "devDependencies": { "...": "string" } }
Extract — paths copied straight from the schema
Schema keys are select paths — copy-paste, no translation. The body is cached from the schema call, so this doesn't re-hit the origin.
// same URL, fields chosen from the schema fetch("https://registry.npmjs.org/hono/latest", select: ["name", "version", "dist.tarball", "dist.unpackedSize", "maintainers[].name"]) { "name": "hono", "version": "4.13.1", "dist": { "tarball": "https://registry.npmjs.org/hono/-/hono-4.13.1.tgz", "unpackedSize": 1376876 }, "maintainers": [ { "name": "yusukebe" } ] }
The answer the agent can now give
Two calls, both tiny — and every value traceable to the captured payload.
hono 4.13.1 — tarball at
registry.npmjs.org/hono/-/hono-4.13.1.tgz,
1,376,876 bytes unpacked (~1.4 MB); maintained
by yusukebe.
Source: registry.npmjs.org/hono/latest, read
8 Aug 2026 [via direct] — ~0.2 KB of a 19.9 KB
document reached the agent, paths straight from
the schema.
The same switch on markdown — the outline
One switch, two shapes: the server picks by what the body actually is. A markdown or text body answers with its heading outline — which is exactly what markdown select targets.
// a README you don't want to pull whole fetch("https://raw.githubusercontent.com/denoland/deno/main/README.md", schema: true) [via direct][schema: markdown outline — 6 headings, 3815 bytes] # Deno ## Installation ### Build and install from source ## Your first Deno program ## Additional resources ## Contributing
Extract the section — whole, verbatim
Markdown select entries are content patterns, not paths — any section containing the pattern returns whole. The body is cached from the outline call, so this doesn't re-hit the origin.
// pattern chosen from the outline fetch("https://raw.githubusercontent.com/denoland/deno/main/README.md", select: ["installation"]) ## Installation … the whole section — every install command, verbatim — and nothing else …
Measured improvement, and where this came from
Discovery plus extraction cost under 1 KB of context against the 19.9 KB document — and the second call never touched the origin. Fields from JSON, sections from markdown, one call shape.
client Claude Code over MCP captured schema, select, outline and section calls — payloads verbatim measured full document 19,877 bytes — capped probe: [truncated at max_bytes=300 of 19877] retention body cached server-side · 24 h — both select calls reused it