# How grep-mcp Manages and Responds to Different HTTP Status Codes from API Calls

> Learn how grep-mcp handles API call HTTP status codes. It uses aiohttp for error handling, mapping codes to exceptions or JSON outputs for consistent agent responses.

- Repository: [gal peretz/grep-mcp](https://github.com/galprz/grep-mcp)
- Tags: how-to-guide
- Published: 2026-02-16

---

**grep-mcp wraps calls to the Grep.app search endpoint inside the asynchronous `grep_query` tool, inspecting HTTP response status with aiohttp and mapping specific codes to custom exceptions or structured JSON outputs to ensure consistent error handling for MCP agents.**

The `grep-mcp` repository provides a Model Context Protocol (MCP) server that interfaces with the Grep.app API. When managing and responding to different HTTP status codes from API calls, the server implements a robust error-handling strategy in [`src/grep_mcp/server.py`](https://github.com/galprz/grep-mcp/blob/main/src/grep_mcp/server.py) that converts technical HTTP responses into user-friendly messages while preserving type safety for downstream consumers.

## HTTP Status Code Mapping in grep_query

The core logic resides in the `grep_query` function within [`src/grep_mcp/server.py`](https://github.com/galprz/grep-mcp/blob/main/src/grep_mcp/server.py). After dispatching requests to `https://grep.app/api/search` using **aiohttp**, the tool evaluates the response status code and branches accordingly.

### Handling 429 Too Many Requests (Rate Limiting)

When the API returns **HTTP 429**, `grep-mcp` raises a dedicated `GrepAPIRateLimitError`. This exception is caught upstream and transformed into a readable error string:

```python

# Result returned to MCP agent

"❌ Error: Rate limit exceeded. Please wait before making another request."

```

This approach prevents raw HTTP errors from propagating to the LLM context while signaling the specific rate-limit condition.

### Handling 404 Not Found (Empty Results)

A **HTTP 404** response does not trigger an exception. Instead, the tool returns a minimal JSON payload indicating zero results:

```python
{
  "total_results": 0,
  "results": []
}

```

This preserves the expected return type of the tool (a JSON string) and allows downstream logic to handle empty result sets gracefully without branching into error-handling code paths.

### Handling 200 OK (Success)

For **HTTP 200** responses, the tool parses the JSON body using `await response.json()` and passes the data to `_format_grep_response`. This helper structures the raw API output into a consistent format suitable for MCP tool responses, extracting relevant fields like repository names, file paths, and code snippets.

### Handling 5xx and Other Client Errors

Any unexpected status code (e.g., **500**, **403**, **502**) triggers a generic `GrepAPIError` containing the specific status code and response text. The outer exception handler converts these into prefixed error messages:

```python
"❌ Error: Unexpected error occurred: <status_code> - <details>"

```

This ensures that even unanticipated API behaviors result in deterministic, user-friendly output rather than stack traces.

## Network-Level Error Management

Beyond HTTP status codes, `grep-mcp` normalizes network-level failures using a hierarchy of custom exceptions defined in [`src/grep_mcp/server.py`](https://github.com/galprz/grep-mcp/blob/main/src/grep_mcp/server.py).

### Timeouts and Connection Failures

When a request exceeds the configured timeout (default 30 seconds), `asyncio.TimeoutError` is caught and re-raised as `GrepAPITimeoutError`. Similarly, `aiohttp` client errors (DNS failures, connection resets, SSL issues) are wrapped in `GrepAPIError`. Both result in consistent error prefixes:

```python
"❌ Error: Request timed out. The grep.app API may be experiencing issues."
"❌ Error: Network error while contacting grep.app API: <details>"

```

### Catch-All Exception Handling

A final `except Exception` block captures any unanticipated errors (parsing failures, unexpected None values, etc.) and returns:

```python
"❌ Error: Unexpected error occurred: <exception_message>"

```

This defensive programming ensures the MCP server never crashes or returns raw Python exceptions to the client, maintaining protocol stability.

## Implementation Details in server.py

The error-handling architecture centers on [`src/grep_mcp/server.py`](https://github.com/galprz/grep-mcp/blob/main/src/grep_mcp/server.py), which contains:

- **`grep_query`**: The main tool function that orchestrates HTTP requests and dispatches to handlers based on status codes.
- **Custom Exception Classes**: `GrepAPIError`, `GrepAPIRateLimitError`, and `GrepAPITimeoutError` provide semantic meaning to failure modes.
- **`_format_grep_response`**: Transforms successful API payloads into MCP-compatible structures.

All network operations use `aiohttp.ClientSession` with explicit timeout configuration, ensuring that asynchronous context managers properly clean up connections regardless of success or failure paths.

## Practical Code Examples

The following examples demonstrate how `grep-mcp` handles various HTTP scenarios:

```python

# Example 1 – Normal successful query

result_json = await grep_query("asyncio.run", language="python")
print(result_json)          # → JSON string with matches

```

```python

# Example 2 – Rate‑limit hit (429)

# Simulate many rapid calls or use a test mock that returns 429

result = await grep_query("foo")

# result == "❌ Error: Rate limit exceeded. Please wait before making another request."

print(result)

```

```python

# Example 3 – Repository not found (404)

result = await grep_query("nonexistentfunction", repo="unknown/unknown")

# Returns a minimal JSON payload with total_results = 0

print(result)

```

```python

# Example 4 – Network timeout

# If the API does not respond within 30 seconds

result = await grep_query("slowquery")

# result == "❌ Error: Request timed out. The grep.app API may be experiencing issues."

print(result)

```

## Summary

- **grep-mcp** maps specific HTTP status codes to custom exceptions in [`src/grep_mcp/server.py`](https://github.com/galprz/grep-mcp/blob/main/src/grep_mcp/server.py), ensuring semantic error handling.
- **HTTP 429** triggers `GrepAPIRateLimitError` and returns a user-friendly rate-limit message.
- **HTTP 404** returns a valid JSON payload with zero results rather than raising an exception.
- **HTTP 200** responses are parsed and formatted via `_format_grep_response` for consistent MCP output.
- **Network failures** (timeouts, connection errors) are normalized through `GrepAPITimeoutError` and `GrepAPIError`.
- All error paths converge on deterministic string outputs prefixed with `❌ Error:`, preventing raw exceptions from reaching MCP clients.

## Frequently Asked Questions

### How does grep-mcp handle rate limiting from the Grep.app API?

When the API returns **HTTP 429 Too Many Requests**, `grep-mcp` raises a `GrepAPIRateLimitError` that gets converted into the message "❌ Error: Rate limit exceeded. Please wait before making another request." This prevents the MCP agent from crashing and signals the user to retry after a delay.

### What happens when the Grep.app API returns a 404 status code?

Rather than treating **HTTP 404** as an error condition, `grep-mcp` returns a minimal JSON payload with `"total_results": 0` and an empty results array. This preserves the tool's expected return type and allows downstream logic to handle empty result sets gracefully without branching into exception handling.

### How are network timeouts and connection errors managed?

Network-level failures such as `asyncio.TimeoutError` or `aiohttp` client errors are caught and wrapped in `GrepAPITimeoutError` or `GrepAPIError` respectively. These are then formatted into user-friendly strings like "❌ Error: Request timed out. The grep.app API may be experiencing issues." ensuring the MCP server remains stable and informative during connectivity issues.

### Where is the HTTP status code handling logic implemented in the codebase?

All HTTP status code inspection and error mapping logic resides in [`src/grep_mcp/server.py`](https://github.com/galprz/grep-mcp/blob/main/src/grep_mcp/server.py), specifically within the `grep_query` asynchronous function. This file defines the custom exception hierarchy (`GrepAPIError`, `GrepAPIRateLimitError`, `GrepAPITimeoutError`) and the `_format_grep_response` helper used for successful response processing.