twentyhq/twenty · error · Exception
MCP Error: {result['error'].get('message', 'Unknown error')}
Error message
MCP Error: {result['error'].get('message', 'Unknown error')} What it means
Raised by TwentyMCP._raw_mcp_call when the raw JSON-RPC response from POST {TWENTY_SERVER_URL}/mcp contains a top-level `error` object. This is the JSON-RPC 2.0 error channel (distinct from execute_tool's success envelope) and fires for protocol/transport-level failures: method not found, invalid params, parse errors, or server-internal errors at the MCP layer. The message uses error.message, defaulting to 'Unknown error'.
Source
Thrown at packages/twenty-server/src/engine/core-modules/tool/tools/code-interpreter-tool/twenty-mcp-helper.const.ts:204
def _raw_mcp_call(self, name: str, arguments: dict = None):
"""Low-level: issue a tools/call against the MCP surface verbatim."""
response = requests.post(
f"{self.url}/mcp",
headers={"Authorization": f"Bearer {self.token}"},
json={
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {"name": name, "arguments": arguments or {}}
},
timeout=30
)
response.raise_for_status()
result = response.json()
if "error" in result:
raise Exception(f"MCP Error: {result['error'].get('message', 'Unknown error')}")
content = result.get("result", {}).get("content", [])
if content and content[0].get("type") == "text":
return json.loads(content[0]["text"])
return result.get("result")
# --------------------------------------------------------------------------
# \`twenty\` is a pre-built instance of the TwentyMCP class above. It is
# already bound in this module scope — DO NOT \`import twenty\`. There is
# no Python package by that name. Just use it directly, e.g.:
# companies = twenty.call_tool('find_many_companies', {'limit': 10})
# --------------------------------------------------------------------------
twenty = TwentyMCP()
`;
View on GitHub (pinned to 1f5dd2bbd2)
Solutions
- Read the embedded message — it is the server's JSON-RPC error detail.
- If the message indicates auth (401/403), rotate/regenerate TWENTY_API_TOKEN and confirm it is current.
- Confirm the tool name exists by calling `learn_tools` (an MCP-native tool) and inspecting the catalog before calling catalog tools.
- Check response.status_code by enriching the helper to log it — raise_for_status runs first, so a JSON-RPC error here means HTTP 200 with an error body, typical of MCP protocol-level failures.
- Verify version alignment between the code-interpreter helper and the Twenty server release.
Example fix
# before — only the message string is surfaced, hard to triage transport vs logic
if "error" in result:
raise Exception(f"MCP Error: {result['error'].get('message', 'Unknown error')}")
# after — include the JSON-RPC error code and HTTP status for faster diagnosis
if "error" in result:
err = result['error']
raise Exception(
f"MCP Error (code={err.get('code')}, http={response.status_code}): "
f"{err.get('message', 'Unknown error')}"
) Defensive patterns
Strategy: try-catch
Validate before calling
# Cheap pre-check: confirm the /mcp endpoint is reachable and the token is accepted before user code calls tools.
import requests, os
def mcp_endpoint_ok() -> bool:
url = os.environ.get('TWENTY_SERVER_URL', '')
token = os.environ.get('TWENTY_API_TOKEN', '')
if not (url and token):
return False
try:
r = requests.post(
f'{url}/mcp',
headers={'Authorization': f'Bearer {token}'},
json={'jsonrpc': '2.0', 'id': 1, 'method': 'tools/list', 'params': {}},
timeout=5,
)
return r.status_code == 200 and 'error' not in r.json()
except requests.RequestException:
return False Type guard
from typing import Any
def is_jsonrpc_error(response: Any) -> bool:
return isinstance(response, dict) and 'error' in response Try / catch
try:
result = twenty.call_tool('find_many_companies', {'limit': 5})
except Exception as e:
msg = str(e)
if msg.startswith('MCP Error:'):
# JSON-RPC level failure — auth, method-not-found, or server error
if 'unauthorized' in msg.lower() or 'forbidden' in msg.lower():
raise RuntimeError('TWENTY_API_TOKEN rejected by /mcp; rotate the token.') from e
if 'method not found' in msg.lower() or 'not found' in msg.lower():
raise RuntimeError('Tool name unknown to this server version; call learn_tools to refresh the catalog.') from e
raise # other server-side JSON-RPC errors
raise Prevention
- Smoke-test the /mcp endpoint with a tools/list call at sandbox startup; fail fast with a clear message.
- Keep the helper version in lockstep with the deployed Twenty server so tool/method names match.
- After any token rotation, redeploy sandboxes so they pick up the new credential rather than emitting JSON-RPC auth errors.
When it happens
Trigger: Calling a tool name the /mcp endpoint does not expose (method/params rejected); the server is up but the MCP surface returned a JSON-RPC error (e.g. auth rejected at the gateway, malformed jsonrpc payload); a server-side exception inside the MCP handler that the framework serializes as a JSON-RPC error rather than an execute_tool failure envelope.
Common situations: Token is expired or revoked (auth middleware rejects before reaching the tool); calling an MCP-native tool name that was renamed or removed in a newer server version; a network proxy returning its own JSON body that happens to contain `error`; version skew between the helper's expected method names and the deployed server.
Related errors
- execute_tool failed for {name}
- Twenty MCP bridge not available. Missing requests library or
- {input_dir} is not a directory
- {output_file} must be a .docx, .pptx, or .xlsx file
- Slide index {idx} out of range (0-{total_slides - 1})
AI-assisted analysis of twentyhq/twenty@1f5dd2bbd2 (2026-08-12).
Data as JSON: /api/errors/68b3d3c3a2914e9a.
Report an issue: GitHub.