perf: shorten all tool docstrings to reduce tools/list payload
Reduced tools/list JSON payload from ~45 KB to 5.7 KB by replacing verbose multi-paragraph docstrings with 1-2 line summaries on all 14 @mcp.tool() functions. Fixes Claude Desktop truncation of tools/list. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -106,10 +106,7 @@ def register_filestation(
|
|||||||
|
|
||||||
@mcp.tool()
|
@mcp.tool()
|
||||||
async def list_shares():
|
async def list_shares():
|
||||||
"""List all shared folders visible to the authenticated user.
|
"""List all shared folders. Returns name/path/volume-usage table."""
|
||||||
|
|
||||||
Returns a formatted table with share name, path, and volume status.
|
|
||||||
"""
|
|
||||||
from mcp_synology_filestation.client import SynologyError
|
from mcp_synology_filestation.client import SynologyError
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -164,23 +161,8 @@ def register_filestation(
|
|||||||
sort_by: str = "name",
|
sort_by: str = "name",
|
||||||
sort_direction: str = "asc",
|
sort_direction: str = "asc",
|
||||||
):
|
):
|
||||||
"""List the contents of a directory on the NAS.
|
"""List directory contents. path: share-relative (e.g. /docker).
|
||||||
|
offset/limit for pagination, sort_by/sort_direction for ordering."""
|
||||||
Use share paths as returned by list_shares (e.g. "/dev", "/data"),
|
|
||||||
not volume paths (e.g. "/volume1/dev" will not work).
|
|
||||||
|
|
||||||
Args:
|
|
||||||
path: Share-relative path on the NAS (e.g. "/dev" or "/data/photos").
|
|
||||||
offset: Number of items to skip (for pagination).
|
|
||||||
limit: Maximum items to return (1-500, default 100).
|
|
||||||
sort_by: Sort field — one of: name, size, user, group, mtime, atime,
|
|
||||||
crtime, posix, type.
|
|
||||||
sort_direction: "asc" or "desc".
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Formatted table with name and type, plus the total item count
|
|
||||||
for pagination context.
|
|
||||||
"""
|
|
||||||
from mcp_synology_filestation.client import SynologyError
|
from mcp_synology_filestation.client import SynologyError
|
||||||
|
|
||||||
# Validate inputs
|
# Validate inputs
|
||||||
@@ -266,21 +248,8 @@ def register_filestation(
|
|||||||
recursive: bool = True,
|
recursive: bool = True,
|
||||||
max_results: int = 200,
|
max_results: int = 200,
|
||||||
):
|
):
|
||||||
"""Search for files matching a glob pattern within a directory.
|
"""Search files by glob pattern under path. pattern: e.g. "*.yaml".
|
||||||
|
recursive/max_results optional."""
|
||||||
Starts an async DSM search task, polls until complete, then cleans up.
|
|
||||||
Use share paths as returned by list_shares (e.g. "/docker").
|
|
||||||
|
|
||||||
Args:
|
|
||||||
path: Root directory to search from (e.g. "/docker").
|
|
||||||
pattern: Filename glob pattern (e.g. "*.yaml", "report*.pdf").
|
|
||||||
recursive: Search subdirectories (default True).
|
|
||||||
max_results: Maximum number of matches to return (default 200, max 1000).
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Formatted table with path, type, size, and modification time,
|
|
||||||
plus total match count.
|
|
||||||
"""
|
|
||||||
from mcp_synology_filestation.client import SynologyError
|
from mcp_synology_filestation.client import SynologyError
|
||||||
|
|
||||||
limit = max(1, min(max_results, 1000))
|
limit = max(1, min(max_results, 1000))
|
||||||
@@ -400,17 +369,8 @@ def register_filestation(
|
|||||||
|
|
||||||
@mcp.tool()
|
@mcp.tool()
|
||||||
async def download(path: str):
|
async def download(path: str):
|
||||||
"""Download a single file from the NAS and return its content as base64.
|
"""Download a file as base64 (max 10 MB). path: share-relative.
|
||||||
|
Returns JSON {filename, size, content_base64}."""
|
||||||
Files larger than 10 MB are rejected — use SFTP or another method instead.
|
|
||||||
Use share paths as returned by list_shares (e.g. "/docker/app/config.yaml").
|
|
||||||
|
|
||||||
Args:
|
|
||||||
path: Absolute share-relative path to the file on the NAS.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
JSON object with "filename", "size" (bytes), and "content_base64".
|
|
||||||
"""
|
|
||||||
import base64
|
import base64
|
||||||
|
|
||||||
from mcp_synology_filestation.client import SynologyError
|
from mcp_synology_filestation.client import SynologyError
|
||||||
@@ -439,19 +399,8 @@ def register_filestation(
|
|||||||
|
|
||||||
@mcp.tool()
|
@mcp.tool()
|
||||||
async def get_info(path: str):
|
async def get_info(path: str):
|
||||||
"""Get detailed metadata for one or more files or folders on the NAS.
|
"""Get metadata (type/size/owner/permissions/timestamps) for one or more paths.
|
||||||
|
path: comma-separated share-relative paths."""
|
||||||
Accepts a single path or a comma-separated list of paths.
|
|
||||||
Use share paths as returned by list_shares (e.g. "/dev/file.txt").
|
|
||||||
|
|
||||||
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 type, size, owner, permissions, and timestamps
|
|
||||||
for each requested path.
|
|
||||||
"""
|
|
||||||
from mcp_synology_filestation.client import SynologyError
|
from mcp_synology_filestation.client import SynologyError
|
||||||
|
|
||||||
paths = [p.strip() for p in path.split(",") if p.strip()]
|
paths = [p.strip() for p in path.split(",") if p.strip()]
|
||||||
@@ -540,22 +489,8 @@ def register_filestation(
|
|||||||
|
|
||||||
@mcp.tool()
|
@mcp.tool()
|
||||||
async def check_exist(path: str):
|
async def check_exist(path: str):
|
||||||
"""Check whether one or more files or folders exist on the NAS.
|
"""Check if one or more paths exist. path: comma-separated share-relative paths.
|
||||||
|
Returns Yes/No table."""
|
||||||
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
|
from mcp_synology_filestation.client import SynologyError
|
||||||
|
|
||||||
paths = [p.strip() for p in path.split(",") if p.strip()]
|
paths = [p.strip() for p in path.split(",") if p.strip()]
|
||||||
@@ -603,17 +538,8 @@ def register_filestation(
|
|||||||
name: str,
|
name: str,
|
||||||
create_parents: bool = False,
|
create_parents: bool = False,
|
||||||
):
|
):
|
||||||
"""Create a new folder on the NAS.
|
"""Create a folder. path: parent dir, name: folder name (not full path).
|
||||||
|
create_parents: make missing parents."""
|
||||||
Args:
|
|
||||||
path: Parent directory path (e.g. "/docker").
|
|
||||||
name: New folder name — not a full path (e.g. "my-app").
|
|
||||||
create_parents: Create missing intermediate parent directories
|
|
||||||
if True (default False).
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Full path of the created folder, or an Error: message.
|
|
||||||
"""
|
|
||||||
from mcp_synology_filestation.client import SynologyError
|
from mcp_synology_filestation.client import SynologyError
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -635,16 +561,8 @@ def register_filestation(
|
|||||||
|
|
||||||
@mcp.tool()
|
@mcp.tool()
|
||||||
async def rename(path: str, new_name: str):
|
async def rename(path: str, new_name: str):
|
||||||
"""Rename a file or folder on the NAS.
|
"""Rename a file or folder. path: current share-relative path,
|
||||||
|
new_name: bare name only (not full path)."""
|
||||||
Args:
|
|
||||||
path: Absolute share-relative path to the item
|
|
||||||
(e.g. "/docker/old-name.yaml").
|
|
||||||
new_name: New name — not a full path (e.g. "new-name.yaml").
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
New absolute path after rename, or an Error: message.
|
|
||||||
"""
|
|
||||||
from mcp_synology_filestation.client import SynologyError
|
from mcp_synology_filestation.client import SynologyError
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -666,19 +584,8 @@ def register_filestation(
|
|||||||
|
|
||||||
@mcp.tool()
|
@mcp.tool()
|
||||||
async def copy(src: str, dst: str, overwrite: bool = False):
|
async def copy(src: str, dst: str, overwrite: bool = False):
|
||||||
"""Copy a file or folder to a new location on the NAS.
|
"""Copy src to dst directory.
|
||||||
|
WARNING: overwrite=True replaces existing items (default False)."""
|
||||||
WARNING: Set overwrite=True only when you intentionally want to replace
|
|
||||||
an existing item at the destination.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
src: Source absolute path (e.g. "/docker/app/compose.yaml").
|
|
||||||
dst: Destination directory path (e.g. "/backup/docker").
|
|
||||||
overwrite: Replace existing item at destination (default False).
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Destination path on success, or an Error: message.
|
|
||||||
"""
|
|
||||||
from mcp_synology_filestation.client import SynologyError
|
from mcp_synology_filestation.client import SynologyError
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -711,19 +618,8 @@ def register_filestation(
|
|||||||
|
|
||||||
@mcp.tool()
|
@mcp.tool()
|
||||||
async def move(src: str, dst: str, overwrite: bool = False):
|
async def move(src: str, dst: str, overwrite: bool = False):
|
||||||
"""Move a file or folder to a new location on the NAS.
|
"""Move src to dst directory.
|
||||||
|
WARNING: overwrite=True replaces existing items (default False)."""
|
||||||
WARNING: Set overwrite=True only when you intentionally want to replace
|
|
||||||
an existing item at the destination.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
src: Source absolute path (e.g. "/docker/app/old-compose.yaml").
|
|
||||||
dst: Destination directory path (e.g. "/backup/docker").
|
|
||||||
overwrite: Replace existing item at destination (default False).
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Destination path on success, or an Error: message.
|
|
||||||
"""
|
|
||||||
from mcp_synology_filestation.client import SynologyError
|
from mcp_synology_filestation.client import SynologyError
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -756,20 +652,8 @@ def register_filestation(
|
|||||||
|
|
||||||
@mcp.tool()
|
@mcp.tool()
|
||||||
async def delete(path: str, confirmed: bool = False):
|
async def delete(path: str, confirmed: bool = False):
|
||||||
"""Delete a file or folder on the NAS.
|
"""Delete a file or folder. IRREVERSIBLE.
|
||||||
|
confirmed=False (default) shows preview only; pass confirmed=True to actually delete."""
|
||||||
WARNING: This operation is irreversible. Without confirmed=True,
|
|
||||||
returns only a preview — no changes are made.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
path: Absolute share-relative path to delete.
|
|
||||||
confirmed: Must be True to actually delete. Defaults to False
|
|
||||||
(preview only — no DSM call).
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Preview message if confirmed=False; success or Error: message
|
|
||||||
if confirmed=True.
|
|
||||||
"""
|
|
||||||
from mcp_synology_filestation.client import SynologyError
|
from mcp_synology_filestation.client import SynologyError
|
||||||
|
|
||||||
if not confirmed:
|
if not confirmed:
|
||||||
@@ -810,25 +694,8 @@ def register_filestation(
|
|||||||
format: str = "zip",
|
format: str = "zip",
|
||||||
password: str = "",
|
password: str = "",
|
||||||
):
|
):
|
||||||
"""Compress files or folders into an archive on the NAS.
|
"""Compress paths into an archive. dest_file_path: full path incl. filename.
|
||||||
|
level: store/fastest/fast/normal/moderate/maximum. format: zip/7z."""
|
||||||
Creates a new archive asynchronously. Progress is polled until the operation
|
|
||||||
completes. Use share paths as returned by list_shares.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
paths: List of share-relative paths to include in the archive
|
|
||||||
(e.g. ["/data/report.pdf", "/data/photos"]).
|
|
||||||
dest_file_path: Full destination path including filename
|
|
||||||
(e.g. "/backup/archive.zip").
|
|
||||||
level: Compression level — "store", "fastest", "fast", "normal",
|
|
||||||
"moderate" (default), or "maximum".
|
|
||||||
mode: Archive write mode — "add" (default), "update", or "refreshen".
|
|
||||||
format: Archive format — "zip" (default) or "7z".
|
|
||||||
password: Optional password to encrypt the archive (default: none).
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Path of the created archive on success, or an Error: message.
|
|
||||||
"""
|
|
||||||
from mcp_synology_filestation.client import SynologyError
|
from mcp_synology_filestation.client import SynologyError
|
||||||
|
|
||||||
_valid_levels = {"store", "fastest", "fast", "normal", "moderate", "maximum"}
|
_valid_levels = {"store", "fastest", "fast", "normal", "moderate", "maximum"}
|
||||||
@@ -880,26 +747,8 @@ def register_filestation(
|
|||||||
create_subfolder: bool = False,
|
create_subfolder: bool = False,
|
||||||
password: str = "",
|
password: str = "",
|
||||||
):
|
):
|
||||||
"""Extract an archive file to a destination folder on the NAS.
|
"""Extract a ZIP or 7z archive to dest_folder_path.
|
||||||
|
overwrite/keep_dir/create_subfolder/password optional."""
|
||||||
Supports ZIP and 7z archives. Runs asynchronously; progress is polled
|
|
||||||
until the extraction completes. Use share paths as returned by list_shares.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
file_path: Share-relative path to the archive file
|
|
||||||
(e.g. "/backup/archive.zip").
|
|
||||||
dest_folder_path: Destination folder for extracted contents
|
|
||||||
(e.g. "/data/extracted").
|
|
||||||
overwrite: Replace existing files at the destination (default False).
|
|
||||||
keep_dir: Preserve the directory structure inside the archive
|
|
||||||
(default True).
|
|
||||||
create_subfolder: Create a subfolder named after the archive to hold
|
|
||||||
extracted contents (default False).
|
|
||||||
password: Password for encrypted archives (default: none).
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Destination folder path on success, or an Error: message.
|
|
||||||
"""
|
|
||||||
from mcp_synology_filestation.client import SynologyError
|
from mcp_synology_filestation.client import SynologyError
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -940,21 +789,8 @@ def register_filestation(
|
|||||||
overwrite: bool = False,
|
overwrite: bool = False,
|
||||||
create_parents: bool = True,
|
create_parents: bool = True,
|
||||||
):
|
):
|
||||||
"""Upload a file to a directory on the NAS from base64-encoded content.
|
"""Upload base64-encoded content as filename into path (max 50 MB).
|
||||||
|
WARNING: overwrite=True replaces existing file (default False)."""
|
||||||
WARNING: Set overwrite=True only when you intentionally want to replace
|
|
||||||
an existing file.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
path: Destination directory path on the NAS (e.g. "/docker/app").
|
|
||||||
filename: Filename to create (e.g. "compose.yaml").
|
|
||||||
content_base64: Base64-encoded file content.
|
|
||||||
overwrite: Replace existing file at destination (default False).
|
|
||||||
create_parents: Create missing parent directories (default True).
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Full path of the uploaded file, or an Error: message.
|
|
||||||
"""
|
|
||||||
import base64
|
import base64
|
||||||
|
|
||||||
from mcp_synology_filestation.client import SynologyError
|
from mcp_synology_filestation.client import SynologyError
|
||||||
|
|||||||
Reference in New Issue
Block a user