MCP
Errors & Troubleshooting
MCP clients need to distinguish transport or protocol errors from tool-level outcomes. A successful JSON-RPC response does not always mean the business action completed — inspect isError, structuredContent.reason_code, structuredContent.tool_output, and structuredContent.execution.status.
Response shapes
1. JSON-RPC error response
Used for protocol, authentication, authorization, session, rate-limit, or unavailable-edge failures.
{
"jsonrpc": "2.0",
"id": "tools-list",
"error": {
"code": -32001,
"message": "Public MCP requests require Authorization: Bearer <api_key>.",
"data": { "code": "authentication_required" }
}
}
2. Tool result with isError: true
tools/call may return HTTP 200 and a JSON-RPC result with isError: true. Treat that as a business failure — inspect structuredContent before retrying.
{
"jsonrpc": "2.0",
"id": "call-send-email",
"result": {
"content": [{ "type": "text", "text": "Tool invocation failed." }],
"structuredContent": {
"reason_code": "sender_profile_unavailable",
"tool_output": {
"error_code": "sender_profile_unavailable",
"error_message": "The default sending domain must finish verification before production email can be sent without from. Provide from explicitly, or verify the default domain."
},
"execution": {
"status": "failed"
}
},
"isError": true
}
}
This example shows sender_profile_unavailable when send_email runs with full_execution and an omitted from while the workspace default sender/domain is not ready for production. Omit from only when that default is configured and verified for production; otherwise confirm production sending setup with the user before retrying, or supply a production-authorized from.
3. Tool result awaiting confirmation (isError: false)
Some production actions pause for explicit human confirmation instead of failing. The JSON-RPC request still succeeds, but isError stays false and structuredContent.execution.status is awaiting_confirmation. No production send has been created yet.
{
"jsonrpc": "2.0",
"id": "call-send-email",
"result": {
"content": [{ "type": "text", "text": "Production email is awaiting explicit confirmation. No production send request or schedule has been created." }],
"structuredContent": {
"reason_code": "explicit_production_confirmation_required",
"tool_output": {
"error_code": "explicit_production_confirmation_required",
"error_message": "explicit_production_confirmation must be true for production execution."
},
"execution": {
"status": "awaiting_confirmation",
"confirmation": {
"required": true,
"required_argument": "explicit_production_confirmation"
}
}
},
"isError": false
}
}
After the user confirms, retry with explicit_production_confirmation: true and a new idempotency_key (for example, production-send-confirmed-002). Do not reuse the idempotency_key from the suspended awaiting_confirmation call.
Common error codes
| Code | Meaning |
|---|---|
authentication_required (401) | Missing bearer credential. |
invalid_bearer_credential (401) | The bearer credential is invalid or could not be authenticated. |
invalid_token (401) | The OAuth token is invalid or expired. |
insufficient_scope (403) | The credential lacks the required scope for this operation. |
workspace_not_accessible (403) | The credential cannot access the requested workspace. |
scope_selection_required (409) | Send X-Workspace-Id — the credential can access multiple workspaces. |
unknown_session | The supplied Mcp-Session-Id is unknown or expired. |
rate_limited | Back off using retry_after_seconds. |
resource_not_found | The resource is not published or not visible for this workspace. |
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Workspace selection error | Your API key can access multiple workspaces and the request did not specify which one to use. | Ask your AI agent: "Ask me to choose a workspace, then retry with the selected workspace ID." |
| No tools are visible | The API key lacks the required scopes. | Confirm the API key scopes in your Constant Contact for Agents account. |
Tool result has isError: true |
The MCP request succeeded, but the business action was rejected or failed. | Ask your AI agent: "My last MCP tool call returned an error. Help me understand what went wrong and how to fix it." |
Tool result has execution.status: "awaiting_confirmation" |
Production send paused for explicit confirmation. The JSON-RPC result keeps isError: false — this is not a failure. |
Confirm intent with the user, then retry with explicit_production_confirmation: true and a new idempotency_key (for example, production-send-confirmed-002). Do not reuse the key from the suspended call. |
Send with draft_id went to production unexpectedly |
draft_id and emails default to full_execution when execution_class is omitted. |
Set execution_class: "test" for sandbox delivery (uses CTCT domain), or include explicit_production_confirmation: true for production sends only when the workspace default sender/domain is configured and verified for production (or supply a production-authorized from). |
from address rejected |
The from address supplied by the caller is not production-authorized for this workspace. |
Leave from empty only when the workspace default sender/domain is configured and verified for production. Otherwise confirm setup with the user before retrying, or supply a different production-authorized from. |
Production send blocked (sender_profile_unavailable or sender_domain_not_verified) |
The workspace default sender/domain is not ready for production, or the supplied from is not production-authorized. |
Confirm production sending setup with the user before retrying. Omit from only when the workspace default sender is ready; otherwise use a different production-authorized from. |
| Email arrived from wrong domain | Expected a different sender domain but got noreply@send.ctct.dev |
This is expected in test mode — test sends always use the CTCT sandbox domain. For production sends, use execution_class: "full_execution" with explicit_production_confirmation: true only when the workspace default sender/domain is configured and verified for production; the backend uses that default when from is omitted. |
explicit_production_confirmation required |
Missing confirmation flag for production send. The response uses isError: false with execution.status: "awaiting_confirmation". |
Confirm intent with the user, then retry full_execution with explicit_production_confirmation: true and a new idempotency_key. |