Skip to content

Commit a2f060d

Browse files
niiish32x越鸿
andauthored
fix: handle non-JSON-serializable objects in MCP tool calls (#150)
Co-authored-by: 越鸿 <nishenghao.nsh@oceanbase.com>
1 parent 6dff36e commit a2f060d

1 file changed

Lines changed: 44 additions & 2 deletions

File tree

  • packages/derisk-serve/src/derisk_serve/agent/resource/tool

packages/derisk-serve/src/derisk_serve/agent/resource/tool/mcp_utils.py

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,45 @@
2222
GptsToolMessages,
2323
)
2424

25+
26+
def _make_json_serializable(obj: Any) -> Any:
27+
"""将对象转换为 JSON 可序列化的格式。
28+
29+
处理包括 AgentFileSystem 等非序列化对象,将其转换为字符串或字典表示。
30+
"""
31+
if obj is None:
32+
return None
33+
if isinstance(obj, (str, int, float, bool)):
34+
return obj
35+
if isinstance(obj, (list, tuple)):
36+
return [_make_json_serializable(item) for item in obj]
37+
if isinstance(obj, dict):
38+
return {k: _make_json_serializable(v) for k, v in obj.items()}
39+
40+
# 处理 AgentFileSystem 和其他常见非序列化类型
41+
type_name = type(obj).__name__
42+
43+
# AgentFileSystem 类型 - 转换为字符串表示
44+
if type_name == "AgentFileSystem":
45+
return f"<AgentFileSystem: {getattr(obj, 'root_path', str(obj))}>"
46+
47+
# Pydantic 模型 - 使用 model_dump 或 dict
48+
if hasattr(obj, "model_dump"):
49+
return _make_json_serializable(obj.model_dump())
50+
if hasattr(obj, "dict"):
51+
return _make_json_serializable(obj.dict())
52+
53+
# dataclass - 使用 asdict
54+
if hasattr(obj, "__dataclass_fields__"):
55+
from dataclasses import asdict
56+
return _make_json_serializable(asdict(obj))
57+
58+
# 其他对象 - 尝试转换为字符串
59+
try:
60+
return str(obj)
61+
except Exception:
62+
return f"<{type_name}: unserializable>"
63+
2564
logger = logging.getLogger(__name__)
2665
tool_cache = TTLCache(maxsize=200, ttl=300)
2766
gpts_tool_messages_dao = GptsToolMessagesDao()
@@ -184,12 +223,15 @@ async def call_mcp_tool(
184223
tool_id = str(uuid.uuid4())
185224

186225
async def call_tool(server: str, arguments: dict):
226+
# 将参数转换为 JSON 可序列化格式,处理 AgentFileSystem 等对象
227+
serializable_arguments = _make_json_serializable(arguments)
228+
187229
gpts_tool_messages = GptsToolMessages(
188230
tool_id=tool_id,
189231
name=mcp_name,
190232
sub_name=tool_name,
191233
type="MCP",
192-
input=json.dumps(arguments, ensure_ascii=False),
234+
input=json.dumps(serializable_arguments, ensure_ascii=False),
193235
success=1,
194236
trace_id=trace_id,
195237
)
@@ -213,7 +255,7 @@ async def call_tool(server: str, arguments: dict):
213255
) as (read, write):
214256
async with ClientSession(read, write) as session:
215257
await session.initialize()
216-
result = await session.call_tool(tool_name, arguments=arguments)
258+
result = await session.call_tool(tool_name, arguments=serializable_arguments)
217259
end_time = int(datetime.now().timestamp() * 1000)
218260
LOGGER.info(
219261
f"[DIGEST][tools/call]mcp_server=[{mcp_name}],sse=[{mcp_server}],success=[Y],err_msg=[],tool=[{tool_name}],costMs=[{end_time - start_time}],result_length=[{len(str(result.json()))}],headers=[{headers}],result:[{result.json()}]"

0 commit comments

Comments
 (0)