From cc3bf023337f2e8a04325d798d81598acff93357 Mon Sep 17 00:00:00 2001 From: sakarpaisen Date: Thu, 22 Oct 2026 16:05:16 +0300 Subject: [PATCH] Add a 2 or 4 space indent option to process_json --- docs/tool-guide.md | 4 ++-- src/mcp_tools_lab/tools/json_tool.py | 12 ++++++++++-- tests/test_json_tool.py | 20 ++++++++++++++++++++ 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/docs/tool-guide.md b/docs/tool-guide.md index ed54a58..a1d19b7 100644 --- a/docs/tool-guide.md +++ b/docs/tool-guide.md @@ -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": "..."}`. diff --git a/src/mcp_tools_lab/tools/json_tool.py b/src/mcp_tools_lab/tools/json_tool.py index bfc2a64..5619a73 100644 --- a/src/mcp_tools_lab/tools/json_tool.py +++ b/src/mcp_tools_lab/tools/json_tool.py @@ -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} diff --git a/tests/test_json_tool.py b/tests/test_json_tool.py index 1c6d98d..ed8d499 100644 --- a/tests/test_json_tool.py +++ b/tests/test_json_tool.py @@ -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}