# How to Implement Global Error Handling in the Instagit MCP API

> Centralize Instagit MCP API errors by assigning a handler to transport.onerror. Capture network failures validation errors and downstream exceptions in one callback.

- Repository: [Lucas Zanoni⠀⠀⠀⠀⠀ ⠀╱|、 ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ (˚ˎ 。7 ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ |、˜〵 ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ じしˍ,)ノ/tcc](https://github.com/castrozan/tcc)
- Tags: how-to-guide
- Published: 2026-02-27

---

**You can centralize all API errors by assigning a handler to `transport.onerror` in `StreamableHttpServerTransport`, which captures network failures, server validation errors, and downstream API exceptions in a single callback.**

The **castrozan/tcc** repository implements a layered error-handling strategy for its Instagit MCP server that ensures no failure goes unobserved. By understanding how errors propagate from the HTTP transport through the MCP server to the downstream API client, you can implement robust global error handling that centralizes logging, monitoring, and recovery logic.

## Understanding the Layered Error Handling Architecture

The Instagit MCP server divides error handling into four distinct layers, each responsible for capturing specific failure modes before bubbling them to a single global handler.

### Transport Layer (HTTP ↔ MCP)

The `StreamableHttpServerTransport` class in [`src/transport/StreamableHttpServerTransport.ts`](https://github.com/castrozan/tcc/blob/main/src/transport/StreamableHttpServerTransport.ts) manages the HTTP server lifecycle and JSON-RPC message parsing. It captures **network-level errors** including socket failures, write errors to streaming responses, and malformed incoming messages. The transport exposes an `onerror` callback (defined at line 61) that receives all transport-level exceptions.

### Server Request Handling Layer

The MCP `Server` instance created in [`src/server.ts`](https://github.com/castrozan/tcc/blob/main/src/server.ts) validates incoming tool calls and session state. When validation fails—such as when a tool ID is missing—the server throws standard `Error` objects (lines 55-58). These errors bubble up to the transport layer, which then forwards them to the `onerror` handler if one is registered.

### API Client Layer

The `ApiClient` class in [`src/api-client.ts`](https://github.com/castrozan/tcc/blob/main/src/api-client.ts) handles downstream HTTP requests to the backend API. It catches `AxiosError` exceptions and re-throws normalized `Error` objects with concise messages (lines 44-48). This normalization ensures that upstream layers remain agnostic of the HTTP client implementation while preserving essential error context like status codes and response bodies.

## Implementing the Global Error Handler

To establish global error handling across the entire API, assign a function to the `onerror` property of your transport instance immediately after creation:

```typescript
import { StreamableHttpServerTransport } from "./src/transport/StreamableHttpServerTransport.js";
import { OpenAPIServer } from "./src/server.js";

const transport = new StreamableHttpServerTransport(8080);

// Global error handling entry point
transport.onerror = (err: Error) => {
  console.error("[GLOBAL ERROR]", err);
  
  // Integrate with external monitoring (Sentry, Datadog, etc.)
  // monitoringClient.captureException(err);
  
  // Implement custom recovery or alerting logic
  if (err.message.includes("ECONNREFUSED")) {
    alertOpsTeam("Backend API unreachable");
  }
};

const server = new OpenAPIServer({
  name: "instagit-mcp",
  version: "1.0.0",
  apiBaseUrl: "https://api.example.com"
});

await server.start(transport);

```

This single callback receives every error from network failures, validation exceptions, and downstream API timeouts, creating a unified observability surface.

## How Errors Propagate Through the System

Understanding the propagation path helps diagnose where to add specific handling logic.

### Transport-Level Network Errors

When the HTTP server fails to start or encounters socket errors during operation, the transport invokes `onerror` directly (lines 87-88). Similarly, write failures to the streaming HTTP response—common when clients disconnect unexpectedly—are caught and forwarded (lines 232-233).

### Server Validation Errors

In [`src/server.ts`](https://github.com/castrozan/tcc/blob/main/src/server.ts), the tool execution handler validates that an `idOrName` parameter exists:

```typescript
if (!idOrName) {
  throw new Error("Tool ID or name is required");
}

```

This error propagates up the call stack to the transport layer. Since the transport wraps request handling in try-catch blocks, it captures the exception and passes it to your `onerror` handler.

### Downstream API Failures

When `ApiClient.executeApiCall` encounters an HTTP error from the backend, it normalizes the exception:

```typescript
catch (error) {
  if (axios.isAxiosError(error)) {
    throw new Error(
      `API request failed: ${error.message}` + 
      (error.response ? ` (${error.response.status}: ${JSON.stringify(error.response.data)})` : "")
    );
  }
  throw error;
}

```

The resulting `Error` bubbles through the server layer to the transport, ultimately reaching your global `onerror` callback with a clean, implementation-agnostic message.

## Key Files for Error Handling

| File | Purpose | Direct Link |
|------|---------|-------------|
| [`src/transport/StreamableHttpServerTransport.ts`](https://github.com/castrozan/tcc/blob/main/src/transport/StreamableHttpServerTransport.ts) | Implements HTTP transport, defines `onerror` callback, forwards parsing/write/network errors | [View on GitHub](https://github.com/castrozan/tcc/blob/master/mcp-openapi-server/src/transport/StreamableHttpServerTransport.ts) |
| [`src/server.ts`](https://github.com/castrozan/tcc/blob/main/src/server.ts) | MCP server setup, validates tool IDs, throws errors that propagate to transport | [View on GitHub](https://github.com/castrozan/tcc/blob/master/mcp-openapi-server/src/server.ts) |
| [`src/api-client.ts`](https://github.com/castrozan/tcc/blob/main/src/api-client.ts) | Executes downstream API calls, catches `AxiosError`, re-throws normalized `Error` | [View on GitHub](https://github.com/castrozan/tcc/blob/master/mcp-openapi-server/src/api-client.ts) |

## Summary

- **Assign a handler to `transport.onerror`** to create a single global error handling entry point for the entire Instagit MCP API.
- **The transport layer** captures network failures, JSON-RPC parsing errors, and streaming write errors (lines 61, 87-88, 232-233, 505-506).
- **Server validation errors** in [`src/server.ts`](https://github.com/castrozan/tcc/blob/main/src/server.ts) (lines 55-58) bubble up to the transport automatically.
- **API client errors** are normalized in [`src/api-client.ts`](https://github.com/castrozan/tcc/blob/main/src/api-client.ts) (lines 44-48) to provide clean, implementation-agnostic error messages upstream.
- **Never swallow errors**—always either log and handle or re-throw so the global handler receives them.

## Frequently Asked Questions

### How do I capture network errors when the HTTP server fails to start?

Network errors during server startup, such as port conflicts or permission issues, are captured by the `StreamableHttpServerTransport` and delivered to your `onerror` callback (lines 87-88). Ensure you assign the `onerror` handler immediately after instantiating the transport, before calling `server.start(transport)`.

### What happens to validation errors thrown by the MCP server?

When the server detects invalid requests—such as missing tool IDs in [`src/server.ts`](https://github.com/castrozan/tcc/blob/main/src/server.ts) (lines 55-58)—it throws standard JavaScript `Error` objects. These exceptions propagate through the transport layer's request handling logic and are automatically forwarded to your global `onerror` handler, allowing you to log or alert on validation failures consistently.

### How are downstream API errors normalized before reaching the global handler?

The `ApiClient` class in [`src/api-client.ts`](https://github.com/castrozan/tcc/blob/main/src/api-client.ts) wraps all HTTP requests in try-catch blocks (lines 44-48). When it catches an `AxiosError`, it extracts the status code and response body, then re-throws a plain `Error` with a descriptive message. This normalization ensures your global error handler receives clean, implementation-agnostic errors without requiring Axios-specific logic in your monitoring code.

### Can I implement different error handling strategies for different error types?

Yes. Since all errors flow through the single `transport.onerror` callback, you can implement conditional logic based on error properties. Inspect `err.message` for specific patterns (such as "ECONNREFUSED" for connection failures or "Tool ID is required" for validation errors) and route them to appropriate handlers—whether that's retry logic, alerting specific teams, or returning different status codes to clients.