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 = [