/api/convert/yaml-to-json
MCP tool yaml_to_json Parses input as YAML 1.2 with the core schema, whatever any %YAML directive says, so yes/no/on/off are strings, 0755 is the decimal 755, and dates stay strings; each such value gets a warning because YAML 1.1 parsers read them differently. Duplicate keys are an error. Aliases are expanded, with at most 1,000 expansions and 200,000 output values (billion-laughs protection); recursive aliases are an error. << merge keys are applied unless merge_keys is false. .inf/.nan and complex (collection) keys are errors; non-string scalar keys become strings with a warning. Tags outside the core schema (!!binary, !!timestamp, !Ref, …) follow custom_tags. Errors give line, column and code.
Browser version (runs locally): YAML Format & Validate.
Try it
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
input required | string (≤ 30000 chars) | — | The YAML text, as a string field or a raw text/plain POST body. |
documents | first | all | first | first converts the first document (with a warning if there are more; no documents gives null). all returns a JSON array with one element per document. |
indent | 2 | 4 | tab | none | 2 | JSON output indentation: 2 or 4 spaces, tab, or none for minified output (no whitespace at all). |
sort_keys | boolean | false | Sort object keys recursively, by UTF-16 code units (the order RFC 8785 uses). Array order never changes. |
merge_keys | boolean | true | Apply << merge keys (YAML 1.1 feature, common in Compose and CI files). false keeps << as an ordinary key. |
custom_tags | error | drop | wrap | error | Values with a tag outside the core schema: error rejects them; drop keeps the value and discards the tag; wrap produces {"<tag>": value}, e.g. {"!Ref": "MyBucket"}. |
Also accepted on every endpoint: format (json | text).
Parameters may come from the query string, a JSON object body, an urlencoded or multipart form,
or (for input) a text/plain body.
Global parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
format | json | text | json | json returns the documented object. text returns only the primary value as text/plain (see "Text output"). |
Response 200 application/json
| Field | Type | Description |
|---|---|---|
json | string | The JSON text, formatted per indent. |
value | any | The same data as a JSON value. |
documentCount | integer | Number of YAML documents in the input. |
warnings | array of object | YAML 1.1/1.2 ambiguities, converted keys, extra documents, large integers. At most 100 are listed. |
warnings[].message | string | Plain-language finding. |
warnings[].line | integer | 1-based line number. |
warnings[].column | integer | 1-based column, counted in Unicode code points. |
warnings[].pointer | string | JSON Pointer of the value in the output. |
Text output (format=text, text/plain): The JSON text.
Errors
Errors are JSON: {"error": "<message>", "code": "<code>", "param": "<name>"?}.
| Status | Code | When |
|---|---|---|
422 | unprocessable_input | The YAML does not parse (the message gives line, column and the library error code), has duplicate keys, uses a value with no JSON equivalent, a custom tag with custom_tags=error, a recursive alias, or exceeds the alias or size limits. |
400 | invalid_parameter | input is longer than 30,000 characters (YAML parsing is the slowest step; use the page for larger files), or an option is not a listed value. |
400 | missing_parameter | A required parameter is absent. |
400 | unknown_parameter | A parameter name is not in the table above (typos are rejected, not ignored). |
413 | payload_too_large | The request body exceeds 1 MiB. |
405 | method_not_allowed | A method other than GET, POST or OPTIONS. |
Behaviour
- Idempotent: the same arguments always return the same result.
-
Requires a client ID and secret (authentication). Each call is
recorded as one metadata row against your client ID; inputs and outputs are never stored or
logged. Responses carry
cache-control: no-store. - CORS: any origin may call this endpoint from a browser, using your credentials.
Examples
Responses below were produced by running each request through this code at build time. Long strings are shortened.
YAML 1.1 pitfalls, anchors and a merge key
curl -X POST 'https://util.caruana.me/api/convert/yaml-to-json' \
-H 'content-type: application/json' \
-d '{"input":"defaults: &defaults\n retries: 3\n country: no\nservice:\n <<: *defaults\n mode: 0755\n port: 8080\n"}'
Response 200
{
"json": "{\n \"defaults\": {\n \"retries\": 3,\n \"country\": \"no\"\n },\n \"service\": {\n \"retries\": 3,\n \"country\": \"no\",\n \"mode\": 755,\n \"port\": 8080\n }\n}",
"value": {
"defaults": {
"retries": 3,
"country": "no"
},
"service": {
"retries": 3,
"country": "no",
"mode": 755,
"port": 8080
}
},
"documentCount": 1,
"warnings": [
{
"message": "no is the string \"no\" in YAML 1.2, but YAML 1.1 parsers read it as a boolean. Quote it to be unambiguous.",
"line": 3,
"column": 12,
"pointer": "/defaults/country"
},
{
"message": "no is the string \"no\" in YAML 1.2, but YAML 1.1 parsers read it as a boolean. Quote it to be unambiguous.",
"line": 3,
"column": 12,
"pointer": "/service/country"
},
{
"message": "0755 is the decimal integer 755 in YAML 1.2, but YAML 1.1 parsers read a leading 0 as octal (493). Write 0o755 for octal, or quote it for a string.",
"line": 6,
"column": 9,
"pointer": "/service/mode"
}
]
}
Same call as an MCP tools/call
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "yaml_to_json",
"arguments": {
"input": "defaults: &defaults\n retries: 3\n country: no\nservice:\n <<: *defaults\n mode: 0755\n port: 8080\n"
}
}
}Several documents
curl -X POST 'https://util.caruana.me/api/convert/yaml-to-json' \
-H 'content-type: application/json' \
-d '{"input":"name: a\n---\nname: b\n","documents":"all","indent":"none"}'
Response 200
{
"json": "[{\"name\":\"a\"},{\"name\":\"b\"}]",
"value": [
{
"name": "a"
},
{
"name": "b"
}
],
"documentCount": 2,
"warnings": []
}
Same call as an MCP tools/call
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "yaml_to_json",
"arguments": {
"input": "name: a\n---\nname: b\n",
"documents": "all",
"indent": "none"
}
}
}CloudFormation-style tags, wrapped
curl -X POST 'https://util.caruana.me/api/convert/yaml-to-json' \
-H 'content-type: application/json' \
-d '{"input":"Bucket: !Ref MyBucket\nArn: !GetAtt [MyBucket, Arn]\n","custom_tags":"wrap"}'
Response 200
{
"json": "{\n \"Bucket\": {\n \"!Ref\": \"MyBucket\"\n },\n \"Arn\": {\n \"!GetAtt\": [\n \"MyBucket\",\n \"Arn\"\n ]\n }\n}",
"value": {
"Bucket": {
"!Ref": "MyBucket"
},
"Arn": {
"!GetAtt": [
"MyBucket",
"Arn"
]
}
},
"documentCount": 1,
"warnings": []
}
Same call as an MCP tools/call
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "yaml_to_json",
"arguments": {
"input": "Bucket: !Ref MyBucket\nArn: !GetAtt [MyBucket, Arn]\n",
"custom_tags": "wrap"
}
}
}