Building an MCP Server That Returns TOON
Tool results dominate agent token budgets. Learn how to return TOON instead of JSON from a Model Context Protocol server, with the input/output format split that keeps it reliable.
To make an MCP server return TOON, serialize your tool result data with a TOON encoder before returning the content string. The model's tool-call arguments stay JSON. This single change cuts the result payload by up to 58.8% on uniform arrays — and because tool results are re-sent every agent loop, the savings compound across every iteration.
Why Tool Results Dominate Agent Token Budgets
In a Model Context Protocol (MCP) agentic loop, the conversation history grows on every turn. When the model calls a tool, the result is inserted back into the context as a new message and then carried forward on every subsequent call. A database query that returns 100 rows serialized as JSON does not just cost tokens once — it costs tokens on every loop iteration until the conversation ends or the context is truncated.
The official toonformat.dev benchmarks measured this concretely: 5,016 LLM calls across 209 questions, six formats, and four models. On flat uniform arrays — exactly the shape of most tool results — TOON used 39.9% fewer tokens overall versus JSON, reaching 58.8% fewer tokens on purely flat table data (67,778 vs 164,452 tokens). With TOON, a 100-row query result that costs 3,000 input tokens as JSON may cost around 1,230 tokens — and that difference is billed on every subsequent loop turn.
The format split matters for a second reason, confirmed by a February 2026 arXiv paper (arXiv 2603.03306): TOON's advantage is strongest for comprehension — the model reading and reasoning over data — not for generation — the model emitting structured output. Tool results feed back to the model for comprehension. Tool-call arguments are generated by the model. This maps cleanly onto the TOON-for-results, JSON-for-args pattern.
Which Parts of an MCP Message Should Use TOON vs JSON?
| MCP message part | Direction | Recommended format | Why |
|---|---|---|---|
| Tool-call arguments emitted by the model | Model → server | JSON | Generation task; arXiv 2603.03306 shows JSON wins on one-shot output accuracy; tool schemas are JSON Schema |
| Tool result returned to the model (large uniform array) | Server → model | TOON | Comprehension task; up to 58.8% fewer tokens on flat tables; 99.6% field retrieval accuracy |
| Tool result returned to the model (small payload, < 10 objects) | Server → model | JSON or plain text | Prompt-tax overhead can exceed savings on tiny results; JSON is zero-instruction-cost |
| Tool result returned to the model (scalar / single value) | Server → model | Plain text | No structure to compress; TOON overhead adds nothing |
For more background on the input-vs-output format split and how it applies to API calls more broadly, see our guide on using TOON with the Vercel AI SDK.
How to Return TOON from an MCP Tool Handler
The change is localized to your tool handler. The MCP protocol passes tool results as a content string; you control what that string contains. Serialize the data as TOON before returning, and include a brief format note in your tool description so the model knows how to read it.
Below is a minimal TypeScript example showing a database query tool returning rows as TOON instead of JSON. The tool-call argument parsing — receiving and validating the model's JSON arguments — is unchanged.
import { encode } from "@toon-format/toon";
// ── Simplified MCP tool handler (pseudocode / illustrative) ──────────────────
const tools = [
{
name: "query_orders",
description:
"Query recent orders. " +
"Result is returned in TOON format: the first line is a header declaring " +
"array length and field names (e.g. orders[N]{field1,field2}:), " +
"followed by comma-separated data rows.",
inputSchema: {
type: "object",
properties: {
customerId: { type: "string" },
limit: { type: "number" },
},
required: ["customerId"],
},
},
];
async function handleToolCall(name: string, args: Record<string, unknown>) {
if (name === "query_orders") {
const { customerId, limit = 50 } = args as {
customerId: string;
limit?: number;
};
// Fetch rows from your data source (stays the same)
const rows = await db.orders.findMany({
where: { customerId },
take: limit,
select: { id: true, date: true, status: true, total: true },
});
// ── Option A: JSON result (verbose) ──────────────────────────────────────
// const resultText = JSON.stringify(rows);
// e.g. 200 rows × ~60 tokens each = ~12,000 input tokens re-sent every loop
// ── Option B: TOON result (compact) ──────────────────────────────────────
const resultText = encode(rows);
// Resulting TOON string (conceptually):
//
// orders[50]{id,date,status,total}:
// ord_001, 2026-05-01, shipped, 149.99
// ord_002, 2026-05-03, pending, 89.50
// ...
//
// Keys declared once → up to 58.8% fewer tokens on this uniform shape
return {
content: [{ type: "text", text: resultText }],
};
}
throw new Error(`Unknown tool: ${name}`);
}The model's tool-call arguments — customerId and limit — arrive as a parsed JSON object, exactly as they would without TOON. Only the result string changes format. The tool description carries the format note that acts as the prompt-tax payment; it is written once and cached by the client, so it does not add cost on every call.
JSON vs TOON Tool Result — Side by Side
To make the token difference concrete, here is the same five-row order result in both formats. Real payloads of 50 or 100 rows amplify this gap proportionally.
// ── JSON result — keys repeated on every row ─────────────────────────────────
[
{"id":"ord_001","date":"2026-05-01","status":"shipped","total":149.99},
{"id":"ord_002","date":"2026-05-03","status":"pending","total":89.50},
{"id":"ord_003","date":"2026-05-04","status":"shipped","total":220.00},
{"id":"ord_004","date":"2026-05-07","status":"cancelled","total":35.00},
{"id":"ord_005","date":"2026-05-09","status":"shipped","total":67.25}
]
// "id", "date", "status", "total" each tokenized 5 times
// Structural glyphs: { } " " , repeated throughout
// ── TOON result — keys declared once, rows are pure values ───────────────────
orders[5]{id,date,status,total}:
ord_001, 2026-05-01, shipped, 149.99
ord_002, 2026-05-03, pending, 89.50
ord_003, 2026-05-04, shipped, 220.00
ord_004, 2026-05-07, cancelled, 35.00
ord_005, 2026-05-09, shipped, 67.25
// Field names appear once in the header; rows contain only values + commasThe TOON version eliminates the per-row repetition of key names and structural punctuation. For a 100-row result, this difference scales directly: the JSON version pays for "id", "date", "status", and "total" as tokens 100 times each; the TOON version pays for them once. This is precisely why the official benchmark recorded 58.8% fewer tokens on flat table data — 67,778 versus 164,452 tokens — as confirmed on toonformat.dev.
When Should You Not Use TOON for MCP Tool Results?
The arXiv study (2603.03306) identifies a non-linear scaling threshold: TOON's efficiency pays off only once the cumulative per-row savings exceed the upfront format-instruction overhead — the prompt tax. For an MCP tool, this overhead is partly paid in the tool description rather than in each result, which reduces the break-even point. Still, there are three cases where TOON is the wrong choice for a tool result:
- Tiny results (fewer than ~10 objects): the per-row savings are small, and the one-time header in the TOON string adds tokens without much return. Return plain JSON or a plain text string instead.
- Non-uniform or deeply nested data: TOON's tabular format is designed for objects that share a schema. On mixed structures, the token reduction falls to 21.9% per the official benchmarks — often not worth the complexity. See our TOON best practices guide for guidance on identifying uniform vs non-uniform payloads.
- Scalar or short-string results: a tool returning a single number, a status string, or a URL has nothing to compress. Return plain text.
The practical heuristic: if your tool result is a uniform array of objects with at least 10 rows and a consistent schema, TOON is likely worth it. If not, default to JSON or plain text and revisit when the result grows.
Stacking TOON with RAG and Multi-Step Agents
The token savings from TOON in tool results are most valuable in multi-step agent workflows, where the conversation context accumulates across many turns. An agent that calls a data-retrieval tool on turn 1 carries that result as context through turns 2, 3, 4, and beyond. A 40% reduction in the result size is a 40% reduction in that portion of the context for every subsequent turn.
For RAG pipelines specifically — where retrieved document chunks are returned as tool results — uniform metadata arrays (document ID, score, date, source) compress well with TOON, while the raw text content is best left as plain text. Our guide to optimizing RAG pipelines with TOON covers exactly this split.
TOON also stacks with prompt caching. Smaller cached blocks are cheaper to write and cheaper to re-read. For the cost arithmetic, see our API cost optimization guide, which covers how token reduction and caching discounts multiply together.
Accuracy Considerations for MCP Tool Results
Returning TOON from a tool does not degrade the model's ability to reason over the result — provided the model supports the format well. The official benchmarks recorded 76.4% overall retrieval accuracy with TOON versus 75.0% with JSON, with field retrieval at 99.6%. For the most common tool-result task — "find the value of field X in row Y" — TOON is essentially lossless.
Accuracy drops for more complex tasks: aggregation at 61.9%, filtering at 56.8%. If your agent needs to aggregate or filter within the result rather than just retrieve values, pre-process the data server-side and return only the relevant rows as TOON, rather than relying on the model to perform the computation over a large TOON payload.
Model choice also matters: Gemini 3 Flash reached 96.7% accuracy with TOON; Claude Haiku 4-5 reached 59.8%. Test your specific model and task type against your actual data before deploying TOON results in production. The free converter at json2toon.co lets you see exactly what your data looks like in TOON before writing any server code.
For a broader view of how the JSON vs TOON decision plays out across different data shapes, see our JSON vs TOON deep-dive.
Frequently Asked Questions
How do I make an MCP server return TOON instead of JSON?
In your MCP tool handler, serialize the result data using a TOON encoder before returning it as the tool result content string. The model's tool-call arguments stay JSON — only the result you return to the model changes format. On uniform arrays of objects, this cuts the result payload by up to 58.8% compared to JSON.
Why does tool result format matter for agent token costs?
In an agentic loop, tool results are injected back into the context on every iteration. A 50-record result serialized as JSON may cost twice as many tokens as the same data in TOON. Because the result is re-sent each loop, the savings compound across iterations and make a significant difference to total billing.
Should the model emit tool-call arguments as TOON?
No. Tool-call arguments are generated by the model, and a 2026 arXiv study (2603.03306) found JSON has the best one-shot and final accuracy for generation tasks. Tool schemas use JSON Schema; the model emits args in JSON natively. Only the result you return to the model — a comprehension task — benefits from TOON.
When is it not worth returning TOON from an MCP tool?
For small results — fewer than roughly 10 objects — the prompt-tax overhead of TOON format instructions can exceed the per-row token savings. The arXiv study (2603.03306) describes this as a non-linear scaling threshold. Simple scalar results (a single number or a short string) should stay as plain text, not TOON.
Which data shapes benefit most from TOON in MCP tool results?
Flat, uniform arrays of objects benefit most — database rows, search results, log entries, time-series records. Official toonformat.dev benchmarks show 58.8% token reduction on flat tables and 59.0% on time-series data. Deeply nested or non-uniform structures save much less (21.9% on mixed data) and may not justify the format overhead.
Recommended Reading
Token-Efficient AI Agents: Using TOON for Tool Calls and MCP Pipelines
How to cut token costs in agent loops and Model Context Protocol servers by passing tool results as TOON instead of JSON, with concrete patterns and caveats.
TOON as the Wire Format for Multi-Agent Systems
In multi-agent systems every message is re-tokenized at each hop, so format overhead compounds. Learn why TOON makes a strong inter-agent wire format and where to keep JSON.
Few-Shot Prompting with TOON: Cheaper, Clearer Examples
Few-shot examples repeat in every prompt, so their format compounds. Learn how TOON-encoding example tables cuts tokens—and why output examples should still match your target format.