您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. import base64
  2. import json
  3. from collections.abc import Generator
  4. from typing import Any, Optional
  5. from core.mcp.error import MCPAuthError, MCPConnectionError
  6. from core.mcp.mcp_client import MCPClient
  7. from core.mcp.types import ImageContent, TextContent
  8. from core.tools.__base.tool import Tool
  9. from core.tools.__base.tool_runtime import ToolRuntime
  10. from core.tools.entities.tool_entities import ToolEntity, ToolInvokeMessage, ToolProviderType
  11. class MCPTool(Tool):
  12. def __init__(
  13. self, entity: ToolEntity, runtime: ToolRuntime, tenant_id: str, icon: str, server_url: str, provider_id: str
  14. ) -> None:
  15. super().__init__(entity, runtime)
  16. self.tenant_id = tenant_id
  17. self.icon = icon
  18. self.server_url = server_url
  19. self.provider_id = provider_id
  20. def tool_provider_type(self) -> ToolProviderType:
  21. return ToolProviderType.MCP
  22. def _invoke(
  23. self,
  24. user_id: str,
  25. tool_parameters: dict[str, Any],
  26. conversation_id: Optional[str] = None,
  27. app_id: Optional[str] = None,
  28. message_id: Optional[str] = None,
  29. ) -> Generator[ToolInvokeMessage, None, None]:
  30. from core.tools.errors import ToolInvokeError
  31. try:
  32. with MCPClient(self.server_url, self.provider_id, self.tenant_id, authed=True) as mcp_client:
  33. tool_parameters = self._handle_none_parameter(tool_parameters)
  34. result = mcp_client.invoke_tool(tool_name=self.entity.identity.name, tool_args=tool_parameters)
  35. except MCPAuthError as e:
  36. raise ToolInvokeError("Please auth the tool first") from e
  37. except MCPConnectionError as e:
  38. raise ToolInvokeError(f"Failed to connect to MCP server: {e}") from e
  39. except Exception as e:
  40. raise ToolInvokeError(f"Failed to invoke tool: {e}") from e
  41. for content in result.content:
  42. if isinstance(content, TextContent):
  43. try:
  44. content_json = json.loads(content.text)
  45. if isinstance(content_json, dict):
  46. yield self.create_json_message(content_json)
  47. elif isinstance(content_json, list):
  48. for item in content_json:
  49. yield self.create_json_message(item)
  50. else:
  51. yield self.create_text_message(content.text)
  52. except json.JSONDecodeError:
  53. yield self.create_text_message(content.text)
  54. elif isinstance(content, ImageContent):
  55. yield self.create_blob_message(
  56. blob=base64.b64decode(content.data), meta={"mime_type": content.mimeType}
  57. )
  58. def fork_tool_runtime(self, runtime: ToolRuntime) -> "MCPTool":
  59. return MCPTool(
  60. entity=self.entity,
  61. runtime=runtime,
  62. tenant_id=self.tenant_id,
  63. icon=self.icon,
  64. server_url=self.server_url,
  65. provider_id=self.provider_id,
  66. )
  67. def _handle_none_parameter(self, parameter: dict[str, Any]) -> dict[str, Any]:
  68. """
  69. in mcp tool invoke, if the parameter is empty, it will be set to None
  70. """
  71. return {
  72. key: value
  73. for key, value in parameter.items()
  74. if value is not None and not (isinstance(value, str) and value.strip() == "")
  75. }