Rejection reasons

MCP call rejections carry error.data.rejectionReason alongside the SDK error code. HTTP transport limits return their HTTP status before a tool pipeline exists. All eleven reasons below are implemented in v3.

Reasons

ReasonProducer / meaning
TOOL_HIDDENCore: direct or dispatcher-mediated call to a hidden tool.
RESOURCE_HIDDENCore: read of a hidden public resource URI.
BACKEND_UNROUTABLEMesh: invalid name or URI prefix, unknown backend, or unsupported target surface.
POLICY_DENIEDPolicy: explicit deny or no matching allow.
IDENTITY_UNRESOLVEDPolicy: no host-resolved caller identity.
CONSENT_MISSINGConsent: missing identity, grant, or successful resolver result.
SENSITIVITY_BLOCKEDPolicy: denied sensitivity tier.
DELEGATION_INVALIDCore: malformed wire chain or a detected caller loop.
BUDGET_EXCEEDEDPolicy: per-session tool/prompt call budget exhausted.
SESSION_LIMITHTTP: maximum live sessions reached, status 503.
BODY_LIMITHTTP: body exceeds maxBodyBytes, status 413.

Auditing rejections

Tool and prompt gates throw inside their pipelines, so an outer audit observer records outcome: 'rejected' and the reason. Place the audit handle last in each proxy middleware array. A plain error without a structured rejection reason is recorded as outcome: 'error'. includeRejections: false opts out of recording refusals. HTTP limits and authentication failures happen before tool execution and do not automatically become tool audit events.

Custom rejections

rejection.ts
import { rejectionMcpError } from 'mcpose';
import { ErrorCode } from '@modelcontextprotocol/sdk/types.js';

throw rejectionMcpError('POLICY_DENIED', ErrorCode.InvalidRequest, 'Call not permitted');