arcade-mcp/libs/arcade-mcp-server/arcade_mcp_server/exceptions.py
Francisco Or Something d9812621de
feat: add NetworkTransportError for no-response HTTP failures (#823)
## Summary

- Adds `NetworkTransportError` — a new sibling to `UpstreamError` under
`ToolExecutionError` — for failures where no complete HTTP response was
received from the upstream service (timeouts, connection errors, pool
exhaustion, DNS failures, decoding issues, redirect exhaustion)
- Routes client-construction bugs (`InvalidURL`, `UnsupportedProtocol`,
`MissingSchema`, `SSLError`, `InvalidHeader`, etc.) to existing
`FatalToolError` instead of `UpstreamError`
- Adds 3 new `ErrorKind` values: `NETWORK_TRANSPORT_RUNTIME_TIMEOUT`,
`_UNREACHABLE`, `_UNMAPPED` — operationally distinct telemetry slices
matching the UpstreamError pattern
- `UpstreamError` is unchanged and reserved for real HTTP responses with
status codes

Addresses Eric's feedback on #820: the `include_status_code=False`
post-init null-out workaround is replaced by a clean class hierarchy
where `NetworkTransportError.status_code` is natively `None`.

### Changes

| File | What |
|---|---|
| `arcade-core/errors.py` | 3 new `ErrorKind` values,
`NetworkTransportError` class, `is_network_transport_error` helper |
| `arcade-tdk/providers/http/error_adapter.py` | Full rewrite of httpx +
requests exception routing with 3-way split |
| `arcade-tdk/providers/graphql/error_adapter.py` |
`TransportConnectionFailed`/`TransportProtocolError` →
`NetworkTransportError` |
| `arcade-tdk/errors.py`, `arcade-mcp-server/exceptions.py` | Re-exports
|
| `pyproject.toml` × 3 | Version bumps: core 4.7.0, tdk 3.7.0,
mcp-server 1.20.0 |
| Tests × 3 | 33 new tests, 3 updated (2659 passed, 0 failures) |

### Exception routing table

| Exception | Target | Kind | can_retry |
|---|---|---|---|
| `httpx.HTTPStatusError`, `requests.HTTPError` (with response) |
`UpstreamError` | status-derived | status-derived |
| `httpx.TimeoutException`, `requests.Timeout` | `NetworkTransportError`
| `TIMEOUT` |  |
| `httpx.TransportError`, `requests.ConnectionError` |
`NetworkTransportError` | `UNREACHABLE` |  |
| `httpx.DecodingError`, `TooManyRedirects`, fallback |
`NetworkTransportError` | `UNMAPPED` | varies |
| `httpx.InvalidURL`/`UnsupportedProtocol`/`LocalProtocolError`,
`requests.MissingSchema`/`SSLError`/etc. | `FatalToolError` |
`TOOL_RUNTIME_FATAL` |  |

### Engine companion PR

ArcadeAI/monorepo — `feat/network-transport-error-kinds` adds the 3
`ErrorKind` constants to Go schemas + OpenAPI docs. No engine logic
changes needed (ErrorKind is a string alias, retry uses `can_retry` flag
only, telemetry auto-slices).

## Test plan

- [x] 2659 existing tests pass (0 failures)
- [x] 33 new routing + class tests added
- [x] mypy clean on arcade-core, arcade-tdk
- [ ] Verify engine telemetry dashboard auto-surfaces new
`NETWORK_TRANSPORT_*` kinds after deploy

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Changes the error taxonomy and classification helpers used for
retries/telemetry, so misclassification could affect operational
behavior, but the change is additive and covered by new tests.
> 
> **Overview**
> Adds a new error category for outbound request failures that never
yield a complete upstream response: `NetworkTransportError` (sibling to
`UpstreamError`) plus
`ErrorKind.NETWORK_TRANSPORT_RUNTIME_{TIMEOUT,UNREACHABLE,UNMAPPED}` and
matching `is_network_transport_error` classification helpers on both
`ToolkitError` and the wire-model `ToolCallError`.
> 
> Re-exports `NetworkTransportError` from `arcade-tdk` and
`arcade-mcp-server`, bumps package versions (`arcade-core` 4.7.0,
`arcade-tdk` 3.7.0, `arcade-mcp-server` 1.20.0) and dependency minimums,
and expands `core/test_errors.py` to cover the new kind
invariants/defaults and classification behavior.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
d2b89078729c6a67ba42684dc98445352238bc1d. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 18:29:13 -03:00

111 lines
2.3 KiB
Python

"""
MCP Exception Hierarchy
Provides domain-specific exceptions for better error handling and debugging.
"""
from arcade_core.errors import (
ContextRequiredToolError,
ErrorKind,
FatalToolError,
NetworkTransportError,
RetryableToolError,
ToolExecutionError,
ToolRuntimeError,
UpstreamError,
UpstreamRateLimitError,
)
__all__ = [
# Re-exports
"ErrorKind",
"FatalToolError",
"NetworkTransportError",
"RetryableToolError",
"ToolExecutionError",
"ToolRuntimeError",
"UpstreamError",
"UpstreamRateLimitError",
"ContextRequiredToolError",
# Base exceptions
"MCPError",
"MCPRuntimeError",
# Server exceptions
"ServerError",
"SessionError",
"RequestError",
"ResponseError",
"ServerRequestError",
"LifespanError",
# Context exceptions
"MCPContextError",
"NotFoundError",
"AuthorizationError",
"PromptError",
"ResourceError",
"TransportError",
"ProtocolError",
]
class MCPError(Exception):
"""Base error for all MCP-related exceptions."""
class MCPRuntimeError(MCPError):
"""Runtime error for all MCP-related exceptions."""
class ServerError(MCPRuntimeError):
"""Error in server operations."""
class SessionError(ServerError):
"""Error in session management"""
class RequestError(ServerError):
"""Error in request processing from client to server"""
class ResponseError(ServerError):
"""Error in request processing from server -> client"""
class ServerRequestError(RequestError):
"""Error in sending request from server -> client initiated by the server"""
class LifespanError(ServerError):
"""Error in lifespan management."""
class MCPContextError(MCPError):
"""Error in context management."""
class NotFoundError(MCPContextError):
"""Requested entity not found."""
class AuthorizationError(MCPContextError):
"""Authorization failure."""
class PromptError(MCPContextError):
"""Error in prompt management."""
class ResourceError(MCPContextError):
"""Error in resource management."""
# Transport and Protocol Errors
class TransportError(MCPRuntimeError):
"""Error in transport layer (stdio, HTTP, etc)."""
class ProtocolError(MCPRuntimeError):
"""Error in MCP protocol handling."""