/api/toml/format
MCP tool toml_format Parses input as TOML 1.0.0 and returns every finding as a diagnostic with a rule ID, severity, line, column and offset: syntax errors, duplicate keys and tables, integers beyond 64 bits (errors); TOML 1.1-only syntax, inconsistent indentation, trailing spaces, mixed line endings (warnings); unnecessary key quotes, split or out-of-order tables, long inline tables, empty tables, long lines (info). Only the first syntax error is reported. An invalid document is a successful response with valid: false, so check valid. For a valid document it also returns the canonical formatting and the data as JSON. Formatting keeps every comment and never changes the data: keys are written key = value with one space around =, indentation and trailing spaces are removed, there is one blank line before each table header, arrays longer than max_line_length are broken one element per line, and the text ends with one line break. Strings, numbers and dates are copied as written. In value, integers beyond ±(2^53 − 1) are decimal strings, inf/nan are the strings "inf", "-inf" and "nan", and dates and times are ISO 8601 strings.
Browser version (runs locally): TOML Format & Validate.
Try it
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
input required | string (≤ 50000 chars) | — | The TOML text. Send it as a string field or as a raw text/plain POST body. |
indent | integer (1–8) | 2 | Spaces per level for arrays that are broken over several lines. |
max_line_length | integer (0–1000) | 120 | Arrays longer than this are broken one element per line, and longer lines are reported (line-length). 0 turns both off. |
sort_keys | boolean | false | Sort keys within each table, by UTF-16 code units. Tables keep their order (the order of [[array]] tables is data). |
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 |
|---|---|---|
valid | boolean | True when there are no error findings. |
summary | object | |
summary.valid | boolean | True when there are no error findings. |
summary.errors | integer | Number of errors. |
summary.warnings | integer | Number of warnings. |
summary.infos | integer | Number of informational findings. |
diagnostics | array of object | Findings in document order. |
diagnostics[].rule | string | Rule ID, e.g. syntax, duplicate-keys, trailing-spaces. |
diagnostics[].severity | "error" | "warning" | "info" | error makes the document invalid; warning and info are style. |
diagnostics[].message | string | What is wrong and how to fix it. |
diagnostics[].line | integer | 1-based line where the problem starts. |
diagnostics[].column | integer | 1-based column (Unicode code points). |
diagnostics[].offset | integer | 0-based UTF-16 offset into the input. |
diagnostics[].endLine optional | integer | 1-based end line, when the problem spans a range. |
diagnostics[].endColumn optional | integer | 1-based end column. |
diagnostics[].endOffset optional | integer | 0-based end offset. |
formatted | string | null | The formatted document, comments kept; null when invalid. |
value | any | The document as JSON (see the value mapping in the docs); null when invalid. |
stats | object | Counts for a valid document; all zero when invalid. |
stats.tables | integer | Tables below the root: [table] sections, dotted-key tables, inline tables and each [[array]] element. |
stats.keys | integer | Keys in all tables. |
stats.arrays | integer | Arrays, including arrays of tables. |
stats.depth | integer | Nesting depth: 1 for a flat document, one more per level of table or array. |
Text output (format=text, text/plain): The formatted TOML, or for invalid input one line: invalid: line L, column C: message.
Errors
Errors are JSON: {"error": "<message>", "code": "<code>", "param": "<name>"?}.
| Status | Code | When |
|---|---|---|
400 | invalid_parameter | input is longer than 50,000 characters, or an option is out of range. Invalid TOML is NOT an error: it returns 200 with valid: false. |
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.
Normalise layout, keeping comments
curl -X POST 'https://util.caruana.me/api/toml/format' \
-H 'content-type: application/json' \
-d '{"input":"# Service settings\ntitle=\"demo\" \n \"port\" = 8080\n[database]\nhosts = [ \"a.example\", \"b.example\" ] # primary first\n[database.pool]\nsize=10\n"}'
Response 200
{
"valid": true,
"summary": {
"valid": true,
"errors": 0,
"warnings": 2,
"infos": 1
},
"diagnostics": [
{
"rule": "trailing-spaces",
"severity": "warning",
"message": "Trailing whitespace.",
"line": 2,
"column": 13,
"offset": 31,
"endLine": 2,
"endColumn": 16,
"endOffset": 34
},
{
"rule": "inconsistent-indentation",
"severity": "warning",
"message": "This key has 2 spaces; the other keys in this table have no indentation.",
"line": 3,
"column": 1,
"offset": 35,
"endLine": 3,
"endColumn": 3,
"endOffset": 37
},
{
"rule": "unnecessary-quotes",
"severity": "info",
"message": "The quotes around \"port\" are not needed: write port.",
"line": 3,
"column": 3,
"offset": 37,
"endLine": 3,
"endColumn": 9,
"endOffset": 43
}
],
"formatted": "# Service settings\ntitle = \"demo\"\nport = 8080\n\n[database]\nhosts = [\"a.example\", \"b.example\"] # primary first\n\n[database.pool]\nsize = 10\n",
"value": {
"title": "demo",
"port": 8080,
"database": {
"hosts": [
"a.example",
"b.example"
],
"pool": {
"size": 10
}
}
},
"stats": {
"tables": 2,
"keys": 6,
"arrays": 1,
"depth": 3
}
}
Same call as an MCP tools/call
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "toml_format",
"arguments": {
"input": "# Service settings\ntitle=\"demo\" \n \"port\" = 8080\n[database]\nhosts = [ \"a.example\", \"b.example\" ] # primary first\n[database.pool]\nsize=10\n"
}
}
}A duplicate key
curl -X POST 'https://util.caruana.me/api/toml/format' \
-H 'content-type: application/json' \
-d '{"input":"[server]\nhost = \"a\"\nport = 80\nhost = \"b\"\n"}'
Response 200
{
"valid": false,
"summary": {
"valid": false,
"errors": 1,
"warnings": 0,
"infos": 0
},
"diagnostics": [
{
"rule": "duplicate-keys",
"severity": "error",
"message": "Duplicate key host: it is already defined in this table.",
"line": 4,
"column": 1,
"offset": 30,
"endLine": 4,
"endColumn": 5,
"endOffset": 34
}
],
"formatted": null,
"value": null,
"stats": {
"tables": 0,
"keys": 0,
"arrays": 0,
"depth": 0
}
}
Same call as an MCP tools/call
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "toml_format",
"arguments": {
"input": "[server]\nhost = \"a\"\nport = 80\nhost = \"b\"\n"
}
}
}Sorted keys and a split table
curl -X POST 'https://util.caruana.me/api/toml/format' \
-H 'content-type: application/json' \
-d '{"input":"[a.x]\nz = 1\ny = 2\n[b]\nk = true\n[a.y]\nk = 1979-05-27T07:32:00Z\n","sort_keys":true}'
Response 200
{
"valid": true,
"summary": {
"valid": true,
"errors": 0,
"warnings": 0,
"infos": 1
},
"diagnostics": [
{
"rule": "table-order",
"severity": "info",
"message": "[a.y] is separated from [a.x] on line 1 by other tables; both belong to a. Keep related tables together.",
"line": 6,
"column": 1,
"offset": 31
}
],
"formatted": "[a.x]\ny = 2\nz = 1\n\n[b]\nk = true\n\n[a.y]\nk = 1979-05-27T07:32:00Z\n",
"value": {
"a": {
"x": {
"z": 1,
"y": 2
},
"y": {
"k": "1979-05-27T07:32:00.000Z"
}
},
"b": {
"k": true
}
},
"stats": {
"tables": 4,
"keys": 8,
"arrays": 0,
"depth": 3
}
}
Same call as an MCP tools/call
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "toml_format",
"arguments": {
"input": "[a.x]\nz = 1\ny = 2\n[b]\nk = true\n[a.y]\nk = 1979-05-27T07:32:00Z\n",
"sort_keys": true
}
}
}