From 4bce8dbad0f2057f03e4334747f2ce7506a41fc1 Mon Sep 17 00:00:00 2001 From: tanjianbin <632190820@qq.com> Date: Sat, 9 May 2026 14:57:42 +0800 Subject: [PATCH] =?UTF-8?q?feat(file=5Ftools):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E8=A7=A3=E6=9E=90JSON=E6=88=96=E6=96=87=E6=9C=AC=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E7=9A=84=E6=96=B0=E5=B7=A5=E5=85=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增 parse_json 工具,用于读取 txt 或 json 文件内容并智能解析。 工具优先尝试将内容解析为JSON,返回结构化数据;若解析失败则作为纯文本返回。 同时更新项目版本号至 0.1.3。 --- file_tools/file_tools/tools.py | 63 ++++++++++++++++++++++++++++++++++ file_tools/pyproject.toml | 2 +- 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/file_tools/file_tools/tools.py b/file_tools/file_tools/tools.py index 599a15c..57202aa 100644 --- a/file_tools/file_tools/tools.py +++ b/file_tools/file_tools/tools.py @@ -120,6 +120,24 @@ tools: List[Tool] = [ }, "required": ["file_path"] } + ), + Tool( + name="parse_json", + description="读取txt或json文件内容,优先按JSON解析并返回结构化数据", + inputSchema={ + "type": "object", + "properties": { + "file": { + "type": "object", + "properties": { + "name": {"type": "string"}, + "content_base64": {"type": "string"} + } + }, + "file_path": {"type": "string"} + }, + "required": [] + } ) ] @@ -430,6 +448,49 @@ def _build_path_data_uri(arguments: Dict[str, Any]) -> str: return _build_data_uri(data, mime_type) +def _build_txt_or_json_result(data: bytes, name: Optional[str]) -> str: + text = data.decode("utf-8-sig") + try: + parsed = json.loads(text) + return json.dumps( + { + "type": "json", + "name": name, + "data": parsed + }, + ensure_ascii=False + ) + except json.JSONDecodeError: + return json.dumps( + { + "type": "text", + "name": name, + "data": text + }, + ensure_ascii=False + ) + + +async def _parse_json(arguments: Dict[str, Any]) -> str: + raw_file_path = str(arguments.get("file_path", "")) + file_path = raw_file_path.strip().strip("`").strip() + if _is_url(file_path): + async with httpx.AsyncClient(follow_redirects=True, timeout=20) as client: + response = await client.get(file_path) + response.raise_for_status() + name = Path(urlparse(file_path).path).name or None + return _build_txt_or_json_result(response.content, name) + + if file_path and file_path != arguments.get("file_path"): + arguments = dict(arguments) + arguments["file_path"] = file_path + + file_info, data, _ = _extract_file_payload(arguments) + if data is None: + raise ValueError("missing file content") + return _build_txt_or_json_result(data, file_info.get("name")) + + async def _build_url_data_uri(arguments: Dict[str, Any]) -> str: url = arguments.get("url") if not url: @@ -519,6 +580,8 @@ async def handle_call_tool(name: str, arguments: Dict[str, Any]) -> List[TextCon if not file_path: raise ValueError("missing file_path") result = await asyncio.to_thread(_upload_file_to_minio_sync, file_path) + elif name == "parse_json": + result = await _parse_json(arguments) else: raise ValueError(f"unknown tool name: {name}") return [TextContent(type="text", text=result)] diff --git a/file_tools/pyproject.toml b/file_tools/pyproject.toml index 6c9e2a6..8151275 100644 --- a/file_tools/pyproject.toml +++ b/file_tools/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "lzwcai-file-tools-mcp" -version = "0.1.1" +version = "0.1.3" description = "File tools MCP server" requires-python = ">=3.10" dependencies = [