From a96a3d460dae9953a379d2b93e1e1c1c8766aa7d Mon Sep 17 00:00:00 2001 From: Marcus van Elst Date: Tue, 14 Apr 2026 09:30:53 +0200 Subject: [PATCH] debug: probe getinfo multi-path formats (comma, path[], JSON array) Co-Authored-By: Claude Sonnet 4.6 --- test_getinfo_multipath.py | 121 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 test_getinfo_multipath.py diff --git a/test_getinfo_multipath.py b/test_getinfo_multipath.py new file mode 100644 index 0000000..225ed4c --- /dev/null +++ b/test_getinfo_multipath.py @@ -0,0 +1,121 @@ +"""Throwaway script: test SYNO.FileStation.List::getinfo with multiple paths. + +Run with: + uv run python test_getinfo_multipath.py + +Tests three variants for passing multiple paths to getinfo and prints the +raw DSM response for each so we know which format the API actually accepts. +""" + +from __future__ import annotations + +import asyncio +import json +import sys + + +# ── config ──────────────────────────────────────────────────────────────── +# Change these to two paths that exist on your NAS (as returned by list_shares +# or list_dir — share-relative, e.g. "/dev/somefile.txt") +PATH_A = "/dev" +PATH_B = "/data" +# ────────────────────────────────────────────────────────────────────────── + + +async def run() -> None: + from mcp_synology_filestation.auth import AuthManager + from mcp_synology_filestation.client import FileStationClient + from mcp_synology_filestation.config import load_config + + config = load_config() + auth = AuthManager(config) + + async with FileStationClient( + config.base_url, + config.connection.verify_ssl, + config.connection.timeout, + ) as client: + await client.query_api_info() + sid = await auth.login(client) + client.sid = sid + + api = "SYNO.FileStation.List" + method = "getinfo" + api_info = client._api_cache[api] + version = api_info["maxVersion"] + url = f"{client._base_url}/webapi/{api_info['path']}" + + print( + f"SYNO.FileStation.List — path={api_info.get('path')!r} " + f"v{api_info.get('minVersion')}-v{api_info.get('maxVersion')}\n" + ) + + additional = json.dumps(["real_path", "size", "time", "perm", "owner", "type"]) + + http = client._http + + # ── Variant 1: comma-separated string ───────────────────────────── + print("─" * 60) + print(f"Variant 1 — path='{PATH_A},{PATH_B}' (comma-separated string)") + base_params = { + "api": api, + "version": str(version), + "method": method, + "_sid": sid, + "additional": additional, + } + params_v1 = {**base_params, "path": f"{PATH_A},{PATH_B}"} + resp = await http.get(url, params=params_v1) + body = resp.json() + print(f" HTTP {resp.status_code} success={body.get('success')}") + if body.get("success"): + files = body.get("data", {}).get("files", []) + print(f" files returned: {len(files)}") + for f in files: + print(f" path={f.get('path')!r} isdir={f.get('isdir')} add={list((f.get('additional') or {}).keys())}") + else: + print(f" ERROR: {body!r}") + print() + + # ── Variant 2: repeated path[] parameters ───────────────────────── + print("─" * 60) + print(f"Variant 2 — path[]={PATH_A!r} & path[]={PATH_B!r} (repeated params)") + # httpx accepts a list of tuples for repeated keys + params_v2_list = list(base_params.items()) + [("path[]", PATH_A), ("path[]", PATH_B)] + resp = await http.get(url, params=params_v2_list) + body = resp.json() + print(f" HTTP {resp.status_code} success={body.get('success')}") + if body.get("success"): + files = body.get("data", {}).get("files", []) + print(f" files returned: {len(files)}") + for f in files: + print(f" path={f.get('path')!r} isdir={f.get('isdir')} add={list((f.get('additional') or {}).keys())}") + else: + print(f" ERROR: {body!r}") + print() + + # ── Variant 3: JSON array ────────────────────────────────────────── + print("─" * 60) + print(f"Variant 3 — path=json.dumps([{PATH_A!r}, {PATH_B!r}]) (JSON array)") + params_v3 = {**base_params, "path": json.dumps([PATH_A, PATH_B])} + resp = await http.get(url, params=params_v3) + body = resp.json() + print(f" HTTP {resp.status_code} success={body.get('success')}") + if body.get("success"): + files = body.get("data", {}).get("files", []) + print(f" files returned: {len(files)}") + for f in files: + print(f" path={f.get('path')!r} isdir={f.get('isdir')} add={list((f.get('additional') or {}).keys())}") + else: + print(f" ERROR: {body!r}") + print() + + await auth.logout(client) + + +if __name__ == "__main__": + try: + asyncio.run(run()) + except Exception as e: + print(f"Fatal: {e}", file=sys.stderr) + sys.exit(1)