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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  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,
  14. entity: ToolEntity,
  15. runtime: ToolRuntime,
  16. tenant_id: str,
  17. icon: str,
  18. server_url: str,
  19. provider_id: str,
  20. headers: Optional[dict[str, str]] = None,
  21. timeout: Optional[float] = None,
  22. sse_read_timeout: Optional[float] = None,
  23. ) -> None:
  24. super().__init__(entity, runtime)
  25. self.tenant_id = tenant_id
  26. self.icon = icon
  27. self.server_url = server_url
  28. self.provider_id = provider_id
  29. self.headers = headers or {}
  30. self.timeout = timeout
  31. self.sse_read_timeout = sse_read_timeout
  32. def tool_provider_type(self) -> ToolProviderType:
  33. return ToolProviderType.MCP
  34. def _invoke(
  35. self,
  36. user_id: str,
  37. tool_parameters: dict[str, Any],
  38. conversation_id: Optional[str] = None,
  39. app_id: Optional[str] = None,
  40. message_id: Optional[str] = None,
  41. ) -> Generator[ToolInvokeMessage, None, None]:
  42. from core.tools.errors import ToolInvokeError
  43. try:
  44. with MCPClient(
  45. self.server_url,
  46. self.provider_id,
  47. self.tenant_id,
  48. authed=True,
  49. headers=self.headers,
  50. timeout=self.timeout,
  51. sse_read_timeout=self.sse_read_timeout,
  52. ) as mcp_client:
  53. tool_parameters = self._handle_none_parameter(tool_parameters)
  54. result = mcp_client.invoke_tool(tool_name=self.entity.identity.name, tool_args=tool_parameters)
  55. except MCPAuthError as e:
  56. raise ToolInvokeError("Please auth the tool first") from e
  57. except MCPConnectionError as e:
  58. raise ToolInvokeError(f"Failed to connect to MCP server: {e}") from e
  59. except Exception as e:
  60. raise ToolInvokeError(f"Failed to invoke tool: {e}") from e
  61. for content in result.content:
  62. if isinstance(content, TextContent):
  63. try:
  64. content_json = json.loads(content.text)
  65. if isinstance(content_json, dict):
  66. yield self.create_json_message(content_json)
  67. elif isinstance(content_json, list):
  68. for item in content_json:
  69. yield self.create_json_message(item)
  70. else:
  71. yield self.create_text_message(content.text)
  72. except json.JSONDecodeError:
  73. yield self.create_text_message(content.text)
  74. elif isinstance(content, ImageContent):
  75. yield self.create_blob_message(
  76. blob=base64.b64decode(content.data), meta={"mime_type": content.mimeType}
  77. )
  78. def fork_tool_runtime(self, runtime: ToolRuntime) -> "MCPTool":
  79. return MCPTool(
  80. entity=self.entity,
  81. runtime=runtime,
  82. tenant_id=self.tenant_id,
  83. icon=self.icon,
  84. server_url=self.server_url,
  85. provider_id=self.provider_id,
  86. headers=self.headers,
  87. timeout=self.timeout,
  88. sse_read_timeout=self.sse_read_timeout,
  89. )
  90. def _handle_none_parameter(self, parameter: dict[str, Any]) -> dict[str, Any]:
  91. """
  92. in mcp tool invoke, if the parameter is empty, it will be set to None
  93. """
  94. return {
  95. key: value
  96. for key, value in parameter.items()
  97. if value is not None and not (isinstance(value, str) and value.strip() == "")
  98. }