feat: add check_exist tool
SYNO.FileStation.CheckExist returns error 400 for every parameter format on this DSM firmware, so the tool falls back to SYNO.FileStation.List::getinfo. DSM returns an entry per requested path with name=None for non-existent paths, which provides a reliable exists/not-exists signal. Accepts a single path or a comma-separated list; returns a table of Path | Exists (Yes/No) with a count footer. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -538,6 +538,63 @@ def register_filestation(
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
@mcp.tool()
|
||||
async def check_exist(path: str) -> str:
|
||||
"""Check whether one or more files or folders exist on the NAS.
|
||||
|
||||
Accepts a single path or a comma-separated list of paths.
|
||||
Use share paths as returned by list_shares (e.g. "/dev/file.txt").
|
||||
|
||||
Note: SYNO.FileStation.CheckExist returns error 400 on this firmware for all
|
||||
parameter formats. This tool falls back to SYNO.FileStation.List::getinfo, which
|
||||
returns an entry per path with name=None when the path does not exist.
|
||||
|
||||
Args:
|
||||
path: One or more share-relative paths, comma-separated
|
||||
(e.g. "/dev/notes.txt" or "/dev/notes.txt,/data/photo.jpg").
|
||||
|
||||
Returns:
|
||||
Formatted table with each path and whether it exists (Yes / No).
|
||||
"""
|
||||
from mcp_synology_filestation.client import SynologyError
|
||||
|
||||
paths = [p.strip() for p in path.split(",") if p.strip()]
|
||||
if not paths:
|
||||
return "Error: no path provided."
|
||||
|
||||
try:
|
||||
data = await client.request(
|
||||
"SYNO.FileStation.List",
|
||||
"getinfo",
|
||||
params={
|
||||
"path": json.dumps(paths),
|
||||
"additional": json.dumps([]),
|
||||
},
|
||||
)
|
||||
except SynologyError as e:
|
||||
return f"Error: {e}"
|
||||
|
||||
files: list[dict] = data.get("files", [])
|
||||
if not files:
|
||||
return "No information returned for the given path(s)."
|
||||
|
||||
# A path that doesn't exist still gets an entry but with name=None
|
||||
rows = [(f.get("path", ""), "Yes" if f.get("name") is not None else "No") for f in files]
|
||||
|
||||
w_path = max(len("Path"), *(len(r[0]) for r in rows))
|
||||
w_exists = len("Exists") # "Yes" / "No" always shorter
|
||||
|
||||
sep = f"+{'-' * (w_path + 2)}+{'-' * (w_exists + 2)}+"
|
||||
header = f"| {'Path':<{w_path}} | {'Exists':<{w_exists}} |"
|
||||
|
||||
lines = [sep, header, sep]
|
||||
for item_path, exists_str in rows:
|
||||
lines.append(f"| {item_path:<{w_path}} | {exists_str:<{w_exists}} |")
|
||||
lines.append(sep)
|
||||
lines.append(f"\n{len(rows)} path(s) checked.")
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
# ── write tools ───────────────────────────────────────────────────────
|
||||
|
||||
@mcp.tool()
|
||||
|
||||
Reference in New Issue
Block a user