# Section 4: Python Tool (check_errors.py + \_\_init\_\_.py)

## Overview

This section creates the Python-side MCP tool for script error checking. It consists of three changes:

1. A new bridge wrapper module at `src/godotiq/tools/bridge/check_errors.py`
2. A new `@mcp.tool()` registration in `src/godotiq/tools/bridge/__init__.py`
3. A new timeout entry in `src/godotiq/bridge/protocol.py`

**Dependency:** Section 2 (check_errors handler in godotiq_server.gd) must be functional on the Godot addon side for the bridge call to succeed at runtime. However, the Python code can be written and tested (via mocks) independently.

---

## Tests First

All tests go in `tests/test_tools/test_check_errors.py`. The testing framework is pytest with `pytest-asyncio` (asyncio_mode = "auto"). The mocking pattern uses `AsyncMock` and `patch("godotiq.tools.bridge.check_errors.get_bridge")`.

### Bridge Wrapper Tests

```python
# Test: check_errors returns clean result when bridge reports no errors
# Test: check_errors forwards errors array from bridge response
# Test: check_errors passes scope parameter to bridge.request
# Test: check_errors defaults scope to "scene" when not specified
# Test: check_errors handles BridgeConnectionError (propagates)
# Test: check_errors handles BridgeTimeoutError (propagates)
# Test: check_errors handles generic BridgeError (propagates)
```

### MCP Registration Tests

```python
# Test: godotiq_check_errors tool is registered in server tool list
# Test: godotiq_check_errors catches BridgeConnectionError → {"error": ..., "hint": ...}
# Test: godotiq_check_errors catches BridgeTimeoutError → {"error": ..., "hint": ...}
# Test: godotiq_check_errors catches BridgeError → {"error": "[CODE] message"}
# Test: godotiq_check_errors applies apply_output_limit to result
```

### Run Pre-check Tests

```python
# Test: run tool reports SCRIPT_ERRORS when bridge returns BridgeError with that code
# Test: run tool proceeds normally when bridge returns success
```

### Timeout Configuration Test

```python
# Test: check_errors has 15s timeout in TOOL_TIMEOUTS
```

---

## Implementation Details

### File 1: `src/godotiq/tools/bridge/check_errors.py`

New module following the pattern of other bridge wrappers (e.g., `run.py`, `perf_snapshot.py`):

```python
async def check_errors(scope: str = "scene") -> dict:
    """Check GDScript files for compilation errors.

    Args:
        scope: "scene" (current scene + autoloads), "project" (all .gd files),
               or a "res://path/to/script.gd" (single file).

    Returns:
        Dict with errors array, total count, scripts_checked, and scope.
    """
```

Body:
1. Call `get_bridge()` from `godotiq.bridge.session`
2. Call `bridge.request("check_errors", params={"scope": scope})`
3. Return the result dict directly

Thin wrapper. No data transformation. `apply_output_limit` is called in the MCP layer, not here.

### File 2: `src/godotiq/tools/bridge/__init__.py`

**Import** (near other bridge wrapper imports):

```python
from godotiq.tools.bridge.check_errors import check_errors as _check_errors
```

**Tool registration:**

```python
@mcp.tool(name="godotiq_check_errors", annotations={...})
async def godotiq_check_errors(scope: str = "scene", ctx: Context = None) -> dict:
    """Check GDScript files for compilation/parse errors.

    Args:
        scope: "scene" (current scene + autoloads), "project" (all .gd files),
               or "res://path/to/script.gd" (single file)
    """
```

- **No `detail` parameter.** Errors don't have meaningful detail levels.
- `annotations`: `readOnlyHint: True`, `destructiveHint: False`, `idempotentHint: True`, `openWorldHint: True`
- Apply `apply_output_limit(result, "normal")` on the result
- Error handling chain: `BridgeConnectionError`, `BridgeTimeoutError`, `BridgeError`, `Exception`
  - `BridgeConnectionError` → `{"error": str(e), "hint": "Enable the GodotIQ addon..."}`
  - `BridgeTimeoutError` → `{"error": str(e), "hint": "The operation timed out. Try a smaller scope."}`
  - `BridgeError` → `{"error": f"[{e.code}] {e.error_message}"}`
  - `Exception` → `{"error": f"Unexpected error: {e}"}`

### File 3: `src/godotiq/bridge/protocol.py`

Add to `TOOL_TIMEOUTS`:

```python
"check_errors": 15.0,
```

15-second timeout for full project scans.

---

## Verification Checklist

1. `pytest tests/test_tools/test_check_errors.py -v` -- all tests green
2. `python -c "from godotiq.tools.bridge.check_errors import check_errors; print('OK')"` -- import succeeds
3. `python -c "from godotiq.bridge.protocol import TOOL_TIMEOUTS; assert TOOL_TIMEOUTS['check_errors'] == 15.0; print('OK')"` -- timeout configured
4. `python -c "import asyncio; from godotiq.server import mcp; tools = asyncio.run(mcp.list_tools()); assert any(t.name == 'godotiq_check_errors' for t in tools); print('OK')"` -- tool registered
5. `pytest -v` -- no regressions in existing tests (1009 passed)

## Implementation Notes (Post-Review)

- Added 3 missing tests from plan: apply_output_limit verification, run SCRIPT_ERRORS test, run happy-path test (15 total)
- Converted test_tool_registered from deprecated sync `run_until_complete` to async `await`
- All files follow existing bridge wrapper patterns exactly
