Files
nocobase-mcp/nocobase_crm_mcp/tool_errors.py
T

85 lines
2.8 KiB
Python

from __future__ import annotations
import os
import subprocess
from collections.abc import Callable
from typing import Any
from .nb_client import NbAuthenticationError, NbCommandError
ENABLE_RAW_DATA_ENV = "NOCOBASE_MCP_ENABLE_RAW_DATA"
def safe_tool_result(operation: Callable[[], dict[str, Any]]) -> dict[str, Any]:
try:
return operation()
except NbAuthenticationError as error:
return tool_error(
code="nb_auth_failed",
message=str(error),
hint=(
"Ask the local installation Agent to run the secure connect-key flow, then enter your personal "
"NocoBase API Key only in the private local prompt."
),
retryable=False,
)
except NbCommandError as error:
return tool_error(
code="nb_command_failed",
message=str(error),
hint="Check nb env status, NocoBase ACL, collection names, and query parameters.",
retryable=False,
)
except subprocess.TimeoutExpired as error:
return tool_error(
code="nb_command_timeout",
message=str(error),
hint="The NocoBase CLI call timed out. Retry with a smaller query or check NocoBase responsiveness.",
retryable=True,
)
except FileNotFoundError as error:
return tool_error(
code="nb_not_found",
message=str(error),
hint="Set NOCOBASE_MCP_NB_BIN to the absolute nb path, then restart with scripts/mcp_service.sh start.",
retryable=False,
)
except Exception as error:
return tool_error(
code="tool_error",
message=str(error),
hint="Check MCP server logs and the CRM mapping config.",
retryable=False,
)
def safe_raw_tool_result(include_raw: bool, operation: Callable[[], dict[str, Any]]) -> dict[str, Any]:
if include_raw and os.environ.get(ENABLE_RAW_DATA_ENV, "").strip() != "1":
return tool_error(
code="raw_data_disabled",
message="Raw NocoBase rows are disabled for this local MCP installation.",
hint=f"Keep include_raw=false, or set {ENABLE_RAW_DATA_ENV}=1 after approving the data exposure policy.",
retryable=False,
)
return safe_tool_result(operation)
def tool_error(*, code: str, message: str, hint: str, retryable: bool) -> dict[str, Any]:
return {"error": {"code": code, "message": message, "hint": hint, "retryable": retryable}}
# Compatibility aliases for internal imports and older tests.
_safe_tool_result = safe_tool_result
_safe_raw_tool_result = safe_raw_tool_result
_tool_error = tool_error
__all__ = [
"ENABLE_RAW_DATA_ENV",
"safe_tool_result",
"safe_raw_tool_result",
"tool_error",
"_safe_tool_result",
"_safe_raw_tool_result",
"_tool_error",
]