Skip to content

Commit 0510651

Browse files
committed
chore: address merge request suggestions
Signed-off-by: Rai Siqueira <rai93siqueira@gmail.com>
1 parent 46be84c commit 0510651

3 files changed

Lines changed: 30 additions & 22 deletions

File tree

README.md

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -477,14 +477,23 @@ Run Django's system checks to identify potential issues in models, settings, and
477477
Read recent lines from file-based log handlers configured in `LOGGING.handlers`.
478478

479479
**Arguments:**
480-
- `lines`: Number of lines to return per file (default: `100`, max: `1000`)
480+
- `lines`: Number of lines to return per file (default: `100`, configurable via `DJANGO_MCP_MAX_LOG_LINES` env var)
481481
- `handler_name`: Optional handler name to read from a single file handler
482482

483-
**Safety and behavior:**
484-
- Reads only handlers backed by `*FileHandler` classes
485-
- Returns structured errors for invalid inputs and missing handlers
486-
- Uses UTF-8 with safe replacement for undecodable bytes
487-
- Returns file existence status without modifying files
483+
> **Note:** This tool reads only file-based handlers (`*FileHandler` classes). If your project logs to the console only, configure a `FileHandler` in your Django `LOGGING` settings so the AI can access log output. Example:
484+
>
485+
> ```python
486+
> LOGGING = {
487+
> "version": 1,
488+
> "handlers": {
489+
> "file": {
490+
> "class": "logging.FileHandler",
491+
> "filename": "django.log",
492+
> },
493+
> },
494+
> "root": {"handlers": ["file"], "level": "INFO"},
495+
> }
496+
> ```
488497
489498
490499
### Prompts
@@ -550,12 +559,6 @@ uv run pytest test_server.py
550559
# Run focused MCP tool tests
551560
uv run pytest test_auth_logic.py test_prompt.py test_query_model.py test_read_recent_logs.py test_run_check.py
552561
553-
# Run a single test file
554-
uv run pytest test_query_model.py
555-
556-
# Run a single test function
557-
uv run pytest test_auth_logic.py::test_validation_logic
558-
559562
# Run the MCP server with the test project
560563
export PYTHONPATH="${PYTHONPATH}:./fixtures/testproject"
561564
uv run django-ai-boost --settings testproject.settings

src/django_ai_boost/server_fastmcp.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -754,7 +754,7 @@ async def read_recent_logs(
754754
Read recent lines from file-based Django log handlers safely.
755755
756756
Args:
757-
lines: Number of recent lines to read per handler (default: 100, max: 1000)
757+
lines: Number of recent lines to read per handler (default: 100, cap set via DJANGO_MCP_MAX_LOG_LINES env var, default cap: 5000)
758758
handler_name: Optional handler name to target one configured handler
759759
760760
Returns:
@@ -763,7 +763,7 @@ async def read_recent_logs(
763763

764764
@sync_to_async
765765
def read_logs():
766-
max_lines = 1000
766+
max_lines = int(os.environ.get("DJANGO_MCP_MAX_LOG_LINES", 5000))
767767

768768
if lines < 1:
769769
return {"error": "lines must be greater than 0"}
@@ -773,20 +773,21 @@ def read_logs():
773773
handlers_config = logging_config.get("handlers", {})
774774

775775
file_handlers: dict[str, Path] = {}
776+
path_errors: dict[str, str] = {}
776777

777778
for name, config in handlers_config.items():
778-
if not isinstance(config, dict):
779-
continue
780-
781779
handler_class = str(config.get("class", ""))
782780
filename = config.get("filename")
783781

784782
if not filename or not handler_class.endswith("FileHandler"):
785783
continue
786784

787-
file_handlers[name] = Path(str(filename)).expanduser().resolve()
785+
try:
786+
file_handlers[name] = Path(str(filename)).expanduser().resolve()
787+
except Exception as e:
788+
path_errors[name] = str(e)
788789

789-
if not file_handlers:
790+
if not file_handlers and not path_errors:
790791
return {"error": "No file-based log handlers found in LOGGING settings"}
791792

792793
if handler_name:
@@ -800,6 +801,9 @@ def read_logs():
800801

801802
logs: list[dict[str, Any]] = []
802803

804+
for name, error_msg in sorted(path_errors.items()):
805+
logs.append({"handler": name, "error": f"Error resolving log file path: {error_msg}"})
806+
803807
for name, file_path in sorted(target_handlers.items()):
804808
log_result: dict[str, Any] = {
805809
"handler": name,
@@ -944,9 +948,9 @@ def run_server(
944948

945949
# Run the server
946950
if transport == "sse":
947-
mcp_server.run(transport="sse", host=host, port=port)
951+
mcp_server.run(transport=transport, host=host, port=port)
948952
else:
949-
mcp_server.run(transport="stdio")
953+
mcp_server.run(transport=transport)
950954

951955

952956
if __name__ == "__main__":

test_read_recent_logs.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ async def test_read_recent_logs_success(
2929
assert any(marker in line for line in result["logs"][0]["lines"])
3030

3131

32-
async def test_read_recent_logs_limit_cap() -> None:
32+
async def test_read_recent_logs_limit_cap(monkeypatch: pytest.MonkeyPatch) -> None:
33+
monkeypatch.setenv("DJANGO_MCP_MAX_LOG_LINES", "1000")
3334
result = await read_recent_logs(lines=9999, handler_name="file")
3435

3536
assert "error" not in result

0 commit comments

Comments
 (0)