new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

MCP Server Development in Practice · all subjects

Schemas and structured output

5 notes, read out of this brain and free to use. Each one was extracted from a source and is re-checked against its exam.

How should I design input schemas so agents don't misuse them?

Models read your JSON Schema as instructions, so design for the misreadings. Rules that hold up in production: (1) Few fields — each optional param is a chance the agent invents a value; make fields required or delete them. (2) Put defaults in the description, not just the schema ('Max results, 1-25. Default 8.') — some clients strip or downweight default fields. (3) Use enums for anything categorical; a freeform string typed by a model will eventually be 'ascending ' with a trailing space. (4) additionalProperties: false, so hallucinated params fail loudly instead of being silently ignored. (5) Validate server-side anyway and return actionable errors ('limit must be 1-25, got 200'), because schema rejection happens client-side in some clients and not at all in others.

Optional parameters — why do agents keep filling them in wrongly?

Because an optional parameter is a suggestion the model feels free to satisfy creatively. Given an optional `since: string` a model will pass 'yesterday', 'last week', or ISO dates with wrong offsets — whatever pattern-matches the conversation. Given optional `category`, it guesses categories that do not exist. Mitigations: make the parameter required when a wrong guess is worse than no guess; constrain with enums or a description that lists valid values ('Reuse an existing category — call list first'); or accept the fuzziness and make the server normalize (case-fold, trim, fuzzy-match, and say what you matched in the response so the agent can correct). The dangerous case is optional params that silently change semantics — filters that narrow results to nothing look like 'the server has no data'.

structuredContent vs text content — which should my tools return?

Both, when you can. Since spec 2025-06-18, a tool can declare an outputSchema and return machine-checkable `structuredContent` alongside the traditional `content` array of text blocks. Clients that support it validate and use the structured form; the text form remains the fallback and is still what most models read most fluently. Practical split: structuredContent carries ids, counts, and machine fields (note_id, results, quota); the text block carries the same facts phrased for the model plus any instructions ('excerpts are cut short; read gives the full note'). Do not dump large JSON into text hoping the model parses it — it will, mostly, until a nested quote breaks its extraction mid-task. Keep text the primary channel until you have verified your target clients consume structuredContent.

When should a tool return ids vs full content?

Return ids plus the minimum to judge relevance, and a second tool to fetch full content — the search/read split. A search tool returning 8 full documents can spend tens of thousands of tokens on results the agent discards after reading titles; returning title + ~150-token excerpt + id lets the agent spend context only on what it opens. This is how production knowledge servers are shaped: search returns ranked excerpts with note_ids and a hint ('excerpts are cut short; read gives the full note'), read takes one id. The same pattern applies to any large payload: list-then-get, page-then-expand. Only inline full content when it is small by construction (a single record lookup) — context is the scarcest resource your tool output consumes.

Tool error vs protocol error — which one do I return?

Use tool errors (result with isError: true and a text explanation) when the tool RAN and failed: bad arguments, rate limit, quota, upstream down, permission denied for this resource. The model sees the message and can adapt — rephrase, wait, tell the user. Use JSON-RPC protocol errors only for protocol-level failures: unknown method (-32601), unknown tool name (-32602 is the pragmatic choice), malformed params that fail schema validation outright, parse errors (-32700). The distinction matters because clients treat them differently: a protocol error means 'your request was wrong', a tool error means 'the world said no'. Classic bug: returning unknown-tool as isError text — a client with a stale tool list reads 'Unknown tool' as an answer and retries the same name forever.

Give your agent this brain