Specification scope: Core with the Import companion specification.
Tool: Structurize is the JSON Structure-focused command-line interface and conversion toolkit from the Avrotize project.
Structurize exposes its conversion catalog through a local Model Context Protocol (MCP) server. An MCP client can discover a conversion, inspect its options, invoke it, and examine the generated files. MCP and CLI invoke the same converter implementation.
Resolve imports before conversion. The Structurize converters tested here
follow local references but do not implement $import or $importdefs.
Structurize parses the closed schema, follows local references, applies its target policy, and writes the artifact.
After conversion, compare the generated artifact with the source constraints.
A PostgreSQL projection may turn required properties into a composite primary
key and store sets, maps, or choices as JSONB; a Parquet projection may turn
a set into a list.
Expose the conversion catalog
Avrotize and Structurize expose the same conversion catalog through a local
Model Context Protocol (MCP) server. Each package installs a console script that
calls avrotize.avrotize:main, and both read the packaged commands.json
registry. Therefore either command is valid when the corresponding package is
installed:
avrotize mcp
structurize mcp
The full Avrotize distribution also installs a dedicated entry point:
avrotize-mcp
The evidence is in Avrotize’s
pyproject.toml,
Structurize’s
pyproject.toml,
and the shared
commands.json.
The server supports stdio only and identifies itself as avrotize, regardless
of which entry point launched it. A client configuration can therefore be as
small as:
{
"mcpServers": {
"avrotize": {
"command": "structurize",
"args": ["mcp"],
"transport": "stdio"
}
}
}
The server exposes four tools:
describe_capabilitiesexplains the server’s purpose and recommended flow.list_conversionsreturns the available conversion and code-generation commands.get_conversionreturns the arguments for one command.run_conversionexecutes that command with an input path or inline content, an output path, and command options.
These names, the avrotize server identity, and the stdio-only check come
directly from
mcp_server.py.
Together with the command registry, they form a discoverable contract. The
agent does not need to guess
that PostgreSQL is spelled postgres or that schema inspection uses
--format schema; it can ask.
In my end-to-end stdio test with Structurize, the server
reported protocol version 2025-03-26, server name avrotize, and exactly those four tools.
describe_capabilities and list_conversions reported 105 conversion
commands, including s2sql and s2pq. get_conversion exposed --dialect
for s2sql and --format for s2pq; those are the options used below.
Discover a conversion before running it
Suppose the fulfillment team wants PostgreSQL DDL and a reviewable Parquet
schema from order.resolved.struct.json. The client follows the tool flow
advertised by the server:
- Call
describe_capabilitiesto confirm that schema conversion is in scope. - Call
list_conversionsand selects2sqlands2pq. - Call
get_conversionfor each command and inspect its required options. - Call
run_conversionwith explicit input and output paths. - Open and inspect the generated artifacts.
I also ran this sequence through MCP.
Both run_conversion calls returned success: true, created the requested
files, and produced files byte-for-byte identical to the equivalent CLI
outputs. The server reports the installed Structurize package version, which
identifies the implementation used for the conversion.
The equivalent CLI operations make the intended arguments easy to see:
New-Item -ItemType Directory -Force generated/postgres, generated/parquet
structurize s2sql order.resolved.struct.json `
--dialect postgres `
--out generated/postgres/order.sql
structurize s2pq order.resolved.struct.json `
--format schema `
--out generated/parquet/order.schema.json
Generated output: order.sql
CREATE TABLE "Order" (
"orderId" VARCHAR(512),
"createdAt" TIMESTAMP,
"tags" JSONB,
"attributes" JSONB,
"destination" JSONB,
PRIMARY KEY ("orderId", "createdAt", "destination")
);
COMMENT ON COLUMN "Order"."tags" IS '{"schema": {"type": "set", "items": {"type": "string"}}}';
COMMENT ON COLUMN "Order"."attributes" IS '{"schema": {"type": "map", "values": {"type": "string"}}}';
COMMENT ON COLUMN "Order"."destination" IS '{"schema": {"type": "choice", "name": "Destination", "choices": {"postal": {"type": "object", "name": "PostalDestination", "properties": {"address": {"type": "string"}}, "required": ["address"]}, "pickupPoint": {"type": "object", "name": "PickupDestination", "properties": {"locationId": {"type": "string"}}, "required": ["locationId"]}}}}';
Generated output: order.schema.json
{
"type": "struct",
"fields": [
{
"name": "orderId",
"type": "string",
"nullable": false
},
{
"name": "createdAt",
"type": "timestamp[us]",
"nullable": false
},
{
"name": "tags",
"type": "list<item: string>",
"nullable": true
},
{
"name": "attributes",
"type": "map<string, string>",
"nullable": true
},
{
"name": "destination",
"type": "struct<postal: struct<address: string not null>, pickupPoint: struct<locationId: string not null>>",
"nullable": false
}
]
}
Explicit output locations matter. Some conversions produce one schema file; code generators may produce a directory of source files, project metadata, and supporting assets. The prebuilt Structurize examples in the Avrotize gallery show representative multi-file projects. An agent should create a dedicated output directory, pass it to the conversion, enumerate what appeared, and inspect one representative file plus the project metadata and supporting assets relevant to the review. A successful tool response is evidence that the function returned. It is not a review of every generated artifact.
What the current tests cover
The MCP tests exercise protocol initialization, all four tools, argument
plumbing, the stdio loop, and a real end-to-end single-file cddl2s
conversion. The Copilot CLI integration tests also exercise single-file schema
conversions with inline content and explicit file paths. See
test_mcp_server.py
and
test_mcp_copilot_cli.py.
Those tests do not establish end-to-end MCP coverage for directory-producing code generation. That does not make directory generation unusable. It means the agent must avoid claiming evidence that the tests do not provide. Use an explicit output directory, inspect the generated tree, and run the target language’s formatter, compiler, and tests where available.
The same evidence boundary applies to imports. The Structurize converters tested here do not
process JSON Structure $import or $importdefs; they resolve local references
only. An agent must first invoke a conforming import resolver and produce a
closed schema, then call s2... on that artifact. It must not silently fetch a
document, splice definitions by intuition, and describe the result as
Structurize output. Source imports are resolved before conversion. Any imports
emitted in generated code or target schemas are target-native artifacts with
their own rules.
Report policy and loss
After generation, compare each artifact with the source constraints and report every constraint the target weakens. The evidence must be the output you inspected or the converter code that produced it. A generic inventory copied from another target is not evidence.
For example, if generated PostgreSQL DDL contains JSONB, cite that DDL and
identify the source set or map contract it no longer expresses as relational
constraints. If the DDL contains a composite PRIMARY KEY, cite it and the
structuretodb.py
policy that collects required properties into the key. If a generated Parquet
schema represents a source set as an Arrow list, cite the inspected schema or
the
structuretoparquet.py
mapping. Make the claim as narrow as its evidence.
My recommendation is that the agent report four things:
- The authoritative input, including the resolved schema artifact and its provenance.
- The exact converter command, options, version or commit, and output path.
- The generated files it inspected and the validation commands it ran.
- The source constraints that the target cannot express or that converter policy changes into target-specific constructs.
It must not synthesize a replacement schema from memory. Re-run with corrected options, apply an explicit target-specific overlay, or file a converter defect.