Building an MCP Server That Returns TOON
Building an MCP server that returns TOON instead of JSON. Tool results dominate agent token budgets; the input/output format split 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 roughly 59% 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 in the current v4.1 run: 5,856 LLM calls across 244 questions, six formats, and four models. Across all datasets TOON used 42.6% fewer tokens than JSON, and on flat uniform arrays (exactly the shape of most tool results) it used 58.7% fewer tokens. With TOON, a 100-row query result that costs 3,000 input tokens as JSON may cost around 1,240 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; 58.7% fewer tokens on flat tables; 97.8% 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. For a working reference, the json2toon.co TOON MCP server does exactly this with its json_to_toon tool, and a handler written in a language without a TOON library can call the TOON API instead.
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({ orders: 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.5
// ...
//
// Keys declared once: roughly 59% 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.5
ord_003,2026-05-04,shipped,220
ord_004,2026-05-07,cancelled,35
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 current official benchmark recorded 58.7% fewer tokens on its flat-only datasets, as reported 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 the official benchmark's mixed-structure track, the reduction falls to 32.7% vs JSON, and TOON ends up about 1.6% larger than compact JSON, so it is 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 current official benchmark recorded 72.2% overall retrieval accuracy with TOON versus 71.4% with JSON, with field retrieval at 97.8% (JSON: 99.2%). For the most common tool-result task, "find the value of field X in row Y", both formats are near the ceiling.
Accuracy drops for more complex tasks in both formats: aggregation at 48.4% (JSON: 48.4%) and filtering at 38.0% (JSON: 41.1%). 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: grok-4.5 reached 97.1% accuracy with TOON, while gpt-5.4-nano reached 57.0% (57.4% with JSON). Test your specific model and task type against your actual data before deploying TOON results in production. The free JSON to TOON converter 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 roughly 59% compared to JSON (58.7% on the official benchmark's flat-only track).
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. The current official toonformat.dev benchmark shows a 58.7% token reduction on its flat-only track and 59.0% on time-series data. Mixed-structure data saves less (32.7% vs JSON, and about 1.6% more tokens than compact JSON), so deeply nested or non-uniform results may not justify the format.
Recommended Reading
Token-Efficient AI Agents: TOON for Tool Calls and MCP
How to cut token costs in AI agent loops and MCP servers by passing tool results as TOON instead of JSON, with concrete patterns and caveats.
TOON as the Wire Format for Multi-Agent Systems
Multi-agent systems re-tokenize every message at each hop, so format overhead compounds. Why TOON is a strong inter-agent wire format, and where to keep JSON.
TOON vs Minified JSON: When Compact JSON Wins
The latest TOON benchmark shows compact JSON beats TOON on mixed, nested data, while TOON wins big on uniform tables. Here is how to choose for your payload.