Output¶
OutputFormat, encoders, and the ToolResult builder.
A tool's result has two halves and they are toggled independently:
structuredContent on the call result, and outputSchema on the tools/list
entry. The MCP spec imposes one asymmetric rule between them — a tool that
advertises outputSchema must return conforming structuredContent, while
the reverse is allowed — so they are not a single switch.
Both are on by default, server-wide via
REST_FRAMEWORK_MCP["INCLUDE_STRUCTURED_CONTENT"] and
["INCLUDE_OUTPUT_SCHEMA"], and per tool via include_structured_content= and
include_output_schema= at registration. The asymmetric rule is enforced:
include_output_schema=True with include_structured_content=False raises at
registration rather than advertising a schema nothing will satisfy.
That is a check on the settings, not on a response. To assert that a real
result satisfies the schema its tool advertised — types and formats, not only
the property names — see
assert_tool_result_conforms.
See Omitting structuredContent and outputSchema
for when to turn either off, and
Hide plumbing from the model for what shapes the
schema an agent sees — field markings project the payload and the advertised
outputSchema from the same declaration.
OutputFormat ¶
Bases: str, Enum
Encoding of a ToolResult's human-readable text block.
Only content[0] varies; structuredContent is always JSON.
Attributes:
| Name | Type | Description |
|---|---|---|
JSON |
Pretty-printed JSON. The safe default. |
|
TOON |
Token-oriented object notation, compact for large uniform arrays.
Falls back to JSON when the optional |
|
AUTO |
Per-payload choice — TOON for a uniform list of objects, JSON otherwise. |
coerce
classmethod
¶
Accept either an enum member or its string value; default to JSON.
encode_json ¶
Encode payload as a stable, pretty JSON string.
default=str renders DRF outputs containing Decimal, UUID or
datetime without raising; keys are sorted so the output is
deterministic.
encode_toon ¶
Encode payload as TOON (token-oriented object notation).
TOON is an optional dependency. Without python-toon installed this
warns and falls back to JSON, so a tool call never breaks because the extra
is absent. The warning fires every time — silence it with
warnings.filterwarnings or install the extra.
The return value alone cannot say which encoder produced it, so a caller
that labels the text — build_tool_result stamps a # format: toon
marker — must ask toon_encoder rather than assume.
build_tool_result ¶
build_tool_result(
payload: Any,
*,
output_format: OutputFormat = OutputFormat.JSON,
is_error: bool = False,
include_structured_content: bool = True,
meta: dict[str, Any] | None = None,
content_kind: ToolContentKind = ToolContentKind.TEXT,
content_mime_type: str | None = None,
binding_name: str | None = None,
) -> ToolResult
Build a ToolResult
for a successful (or tool-level error) call.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
payload
|
Any
|
The JSON-shaped tool output. Becomes |
required |
output_format
|
OutputFormat
|
How |
JSON
|
is_error
|
bool
|
Stamped onto the result as |
False
|
include_structured_content
|
bool
|
|
True
|
meta
|
dict[str, Any] | None
|
The base protocol's |
None
|
content_kind
|
ToolContentKind
|
The block type the binding declared. Anything other than
|
TEXT
|
content_mime_type
|
str | None
|
Media type for a non- |
None
|
binding_name
|
str | None
|
Names the binding in that mismatch message. |
None
|
A None payload is a result with nothing to present: an
allow_none RETRIEVE that found no row, a service whose output re-read
selector found none, or a service with no re-read declaring
ServiceSpec(allow_none=True) that returned None. It is served as
{}, both as structuredContent and as the text block, because MCP
requires structured content to be an object and asks the text block to
carry the same JSON. This is the one place the rule lives, so a selector, a
service and a chain answer it the same way on every entry point. The
advertised outputSchema of those tools admits the {}
(build_output_schema(may_be_empty=...)). A service with no re-read that
returns None without declaring allow_none is served {} too,
against a schema that still requires its fields, because drf-services
presents an undeclared None rather than refusing it
(test_an_undeclared_none_is_still_served_empty_against_a_strict_schema);
allow_none=True
is the declaration that makes the schema admit it
(test_a_service_declaring_allow_none_serves_an_empty_object_its_schema_admits).