Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/tool-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ with ties ordered by first appearance. Lines follow `str.splitlines()`:
empty input has zero lines and a final newline does not add an extra line.
Sentence counting is a simple split on `.`, `!`, and `?`, not language-aware analysis.

## process_json(text, action="format", sort_keys=False)
## process_json(text, action="format", sort_keys=False, indent=2)

Actions are `validate`, `format`, and `minify`. Formatting uses two spaces.
Actions are `validate`, `format`, and `minify`. Formatting uses two spaces by default; pass `indent=4` for four spaces (`indent` accepts only 2 or 4 and is validated for every action, even though it only affects formatted output).
`process_json('{"a": 1}', action="minify")` returns
`{"valid": True, "output": '{"a":1}'}`. Validation returns only `valid` on success.
Malformed input returns `{"valid": False, "error": "..."}`.
Expand Down
12 changes: 10 additions & 2 deletions src/mcp_tools_lab/tools/json_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,25 @@ def process_json(
text: str,
action: Literal["validate", "format", "minify"] = "format",
sort_keys: bool = False,
indent: int = 2,
) -> dict:
"""Validate or format JSON using Python numbers; pretty output uses two spaces."""
"""Validate or format JSON using Python numbers.

Pretty output (action="format") uses `indent` spaces; only 2 or 4 are
supported, defaulting to 2. `indent` must still be valid (2 or 4) for
every action, even when it does not affect minify or validate output.
"""
if action not in {"validate", "format", "minify"}:
raise ValueError("action must be validate, format, or minify.")
if indent not in (2, 4):
raise ValueError("indent must be 2 or 4.")
try:
value = json.loads(text, parse_constant=_reject_constant, parse_float=_finite_float)
if action == "validate":
return {"valid": True}
output = json.dumps(
value, ensure_ascii=False, sort_keys=sort_keys, allow_nan=False,
indent=2 if action == "format" else None,
indent=indent if action == "format" else None,
separators=None if action == "format" else (",", ":"),
)
return {"valid": True, "output": output}
Expand Down
20 changes: 20 additions & 0 deletions tests/test_json_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,23 @@ def test_scalar_and_container_validation(text):
def test_unknown_action():
with pytest.raises(ValueError, match="action"):
process_json("{}", "unknown")
def test_default_indent_is_two_spaces():
assert process_json('{"a":1}')["output"] == '{\n "a": 1\n}'
assert process_json('{"a":1}', indent=2)["output"] == '{\n "a": 1\n}'
def test_indent_four():
assert process_json('{"a":1}', indent=4)["output"] == '{\n "a": 1\n}'
def test_nested_indent():
result = process_json('{"outer":{"inner":1}}', indent=4)
assert result["output"] == '{\n "outer": {\n "inner": 1\n }\n}'
result = process_json('{"outer":{"inner":1}}')
assert result["output"] == '{\n "outer": {\n "inner": 1\n }\n}'
def test_indent_is_validated_for_every_action():
with pytest.raises(ValueError, match="indent"):
process_json("{}", "minify", indent=3)
with pytest.raises(ValueError, match="indent"):
process_json("{}", "validate", indent=0)
with pytest.raises(ValueError, match="indent"):
process_json("{}", indent=-2)
# Valid indent keeps existing minify and validate behavior unchanged.
assert process_json('{"a":1}', "minify", indent=4)["output"] == '{"a":1}'
assert process_json('{"a":1}', "validate", indent=4) == {"valid": True}
Loading