Use this page when you want to know what happens after something throws in a schema, plugin, middleware, or handler.Documentation Index
Fetch the complete documentation index at: https://redop.useagents.site/docs/llms.txt
Use this file to discover all available pages before exploring further.
How Redop resolves errors
Redop resolves execution failures by MCP operation type:| Operation | What the client receives |
|---|---|
tools/call | A tool result with isError: true |
resources/read | A JSON-RPC error object |
prompts/get | A JSON-RPC error object |
- schema validation
- plugin middleware
- global middleware
- tool, resource, or prompt middleware
- the handler itself
What happens when a plugin or handler throws
If middleware or a handler throws, Redop does three things:- It stops the current execution path.
- It runs
onError(...)hooks. - It converts the failure into the client-facing response for that MCP operation.
Example: throw from plugin middleware
This example rejects requests that do not include anx-tenant-id header.
x-tenant-id is missing, the request never reaches the handler.
What a tool client receives
If that failure happens duringtools/call, Redop returns a normal tool result with isError: true.
result instead of the top-level JSON-RPC error field.
What a resource or prompt client receives
If the same kind of failure happens duringresources/read or prompts/get, Redop returns a JSON-RPC error object instead.
-32602 for these execution failures in HTTP and stdio transports.
Where to throw errors
Throw in the layer that owns the failure.Use schemas for input validation
Use schemas for:- missing required fields
- invalid types
- string length checks
- enum and value constraints
Use middleware for request policy
Use middleware for:- authentication
- authorization checks based on headers or request metadata
- tenant resolution
- rate limits
- request-scoped setup that must exist before the handler runs
Use handlers for business logic failures
Use handlers for:- missing records
- invalid domain transitions
- failed external operations
- permission checks that depend on loaded business data
Post not found: 123Forbidden: missing scope 'admin'Invoice is already paid
What onError(...) is for
onError(...) is for shared observability. It can log, trace, or count failures, but it does not redefine the transport behavior above.
onError(...) for:
- logging
- metrics
- tracing
- alerting
- audit records
What happens in after(...) and afterResponse(...)
after(...) runs after a successful handler result exists. If an after(...) hook throws, Redop reports that failure to error hooks, but it does not replace the original successful result.
afterResponse(...) runs after Redop has already finished the response. If it throws, Redop can still send that failure to error hooks, but the client response is already complete and cannot be changed.
Use these hooks for best-effort work such as:
- analytics
- metrics
- logging
- notifications
Use McpError when you need protocol intent
Redop exports McpError and McpErrorCode for cases where you want to model an explicit MCP-aware failure instead of a generic application exception.
For most application code, a normal Error is still the simplest choice. Reach for McpError when you want the failure itself to carry protocol-level meaning.
Practical rules
- Throw in schemas for input shape and field rules.
- Throw in middleware for request policy.
- Throw in handlers for business logic.
- Use
onError(...)for shared observability. - Keep error messages specific enough for humans and agents to act on.
- Do not rely on
after(...)orafterResponse(...)for mandatory logic.