files-com-mcp 1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- files_com_mcp-1.0/LICENSE +21 -0
- files_com_mcp-1.0/PKG-INFO +84 -0
- files_com_mcp-1.0/README.md +69 -0
- files_com_mcp-1.0/files_com_mcp/__init__.py +3 -0
- files_com_mcp-1.0/files_com_mcp/__main__.py +31 -0
- files_com_mcp-1.0/files_com_mcp/authored_tools/__init__.py +4 -0
- files_com_mcp-1.0/files_com_mcp/authored_tools/check_platform_status.py +18 -0
- files_com_mcp-1.0/files_com_mcp/authored_tools/debug.py +8 -0
- files_com_mcp-1.0/files_com_mcp/authored_tools/local_transfer.py +59 -0
- files_com_mcp-1.0/files_com_mcp/generated_tools/__init__.py +1 -0
- files_com_mcp-1.0/files_com_mcp/generated_tools/automation.py +151 -0
- files_com_mcp-1.0/files_com_mcp/generated_tools/bundle.py +175 -0
- files_com_mcp-1.0/files_com_mcp/generated_tools/bundle_download.py +37 -0
- files_com_mcp-1.0/files_com_mcp/generated_tools/bundle_notification.py +166 -0
- files_com_mcp-1.0/files_com_mcp/generated_tools/bundle_recipient.py +84 -0
- files_com_mcp-1.0/files_com_mcp/generated_tools/bundle_registration.py +37 -0
- files_com_mcp-1.0/files_com_mcp/generated_tools/file.py +134 -0
- files_com_mcp-1.0/files_com_mcp/generated_tools/folder.py +71 -0
- files_com_mcp-1.0/files_com_mcp/generated_tools/group.py +172 -0
- files_com_mcp-1.0/files_com_mcp/generated_tools/history.py +152 -0
- files_com_mcp-1.0/files_com_mcp/generated_tools/permission.py +112 -0
- files_com_mcp-1.0/files_com_mcp/generated_tools/remote_server.py +61 -0
- files_com_mcp-1.0/files_com_mcp/generated_tools/user.py +238 -0
- files_com_mcp-1.0/files_com_mcp/patches/__init__.py +1 -0
- files_com_mcp-1.0/files_com_mcp/patches/fastmcp_settings_patch.py +12 -0
- files_com_mcp-1.0/files_com_mcp/server.py +31 -0
- files_com_mcp-1.0/files_com_mcp/utils.py +25 -0
- files_com_mcp-1.0/files_com_mcp.egg-info/PKG-INFO +84 -0
- files_com_mcp-1.0/files_com_mcp.egg-info/SOURCES.txt +33 -0
- files_com_mcp-1.0/files_com_mcp.egg-info/dependency_links.txt +1 -0
- files_com_mcp-1.0/files_com_mcp.egg-info/requires.txt +5 -0
- files_com_mcp-1.0/files_com_mcp.egg-info/top_level.txt +3 -0
- files_com_mcp-1.0/pyproject.toml +40 -0
- files_com_mcp-1.0/setup.cfg +4 -0
- files_com_mcp-1.0/tests/test_utils.py +27 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2019- Action Verb, LLC (https://www.files.com)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: files_com_mcp
|
|
3
|
+
Version: 1.0
|
|
4
|
+
Summary: MCP for the Files.com API
|
|
5
|
+
License: MIT
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Requires-Dist: fastmcp>=2.2.0
|
|
10
|
+
Requires-Dist: mcp
|
|
11
|
+
Requires-Dist: files-com
|
|
12
|
+
Requires-Dist: requests>=2.31.0
|
|
13
|
+
Requires-Dist: fastapi
|
|
14
|
+
Dynamic: license-file
|
|
15
|
+
|
|
16
|
+
# Files.com Python MCP Server
|
|
17
|
+
|
|
18
|
+
Files.com MCP provides tools that are a subset of our APIs offering our most popular operations.
|
|
19
|
+
|
|
20
|
+
## Important Information
|
|
21
|
+
|
|
22
|
+
Some LLMs struggle with too many tools in the context. LLM clients often offer a way to disable and enable specific tools for an MCP. If your LLM is having trouble picking the right tools, try disabling the tools you do not need in your LLM client.
|
|
23
|
+
|
|
24
|
+
## Installing in Claude
|
|
25
|
+
|
|
26
|
+
To install into Claude you have to add JSON to the `claude_desktop_config.json`
|
|
27
|
+
|
|
28
|
+
An official tutorial can found here: https://modelcontextprotocol.io/quickstart/user#2-add-the-filesystem-mcp-server
|
|
29
|
+
|
|
30
|
+
To add our MCP, add the following JSON (be sure to change the path and FILESCOM_API_KEY value)
|
|
31
|
+
|
|
32
|
+
NOTE: This version assumes you are running from source. Once we have PyPi publishing this README will have them version as well.
|
|
33
|
+
|
|
34
|
+
### uv Required
|
|
35
|
+
|
|
36
|
+
These examples requires `uv` which is a popular modern environment manager for running isolated python tools. Installation is out of scope of this README.
|
|
37
|
+
|
|
38
|
+
### Claude Config - STDIO
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
{
|
|
42
|
+
"mcpServers": {
|
|
43
|
+
"files_com_mcp": {
|
|
44
|
+
"type": "stdio",
|
|
45
|
+
"command": "uv",
|
|
46
|
+
"args": [
|
|
47
|
+
"--directory",
|
|
48
|
+
"/path/to/folder-containing-files_com_mcp",
|
|
49
|
+
"run",
|
|
50
|
+
"-m",
|
|
51
|
+
"files_com_mcp"
|
|
52
|
+
],
|
|
53
|
+
"env": {
|
|
54
|
+
"FILES_COM_API_KEY": "CHangeME"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Development
|
|
62
|
+
|
|
63
|
+
While our MCP works well out-of-the-box, some power users find value in modifying MCP code to suit their unique needs. For those power users, it is recommended to use STDIO mode. Upload and Download tools rely on the file system where the MCP is running.
|
|
64
|
+
|
|
65
|
+
To test LLM tools we recommend a popular command-line program called `inspector`. This will start a WebUI on a local port, the output of the command will give you the link to the inspector GUI.
|
|
66
|
+
Ex: http://127.0.0.1:6274
|
|
67
|
+
|
|
68
|
+
## Develoment - STDIO
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
FILESCOM_API_KEY="dummyKey" npx @modelcontextprotocol/inspector uv run -m files_com_mcp
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Development - SSE
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
FILESCOM_API_KEY="dummyKey" uv run -m files_com_mcp --mode server --port 12345
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Launch the inspector
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
npx @modelcontextprotocol/inspector
|
|
84
|
+
```
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Files.com Python MCP Server
|
|
2
|
+
|
|
3
|
+
Files.com MCP provides tools that are a subset of our APIs offering our most popular operations.
|
|
4
|
+
|
|
5
|
+
## Important Information
|
|
6
|
+
|
|
7
|
+
Some LLMs struggle with too many tools in the context. LLM clients often offer a way to disable and enable specific tools for an MCP. If your LLM is having trouble picking the right tools, try disabling the tools you do not need in your LLM client.
|
|
8
|
+
|
|
9
|
+
## Installing in Claude
|
|
10
|
+
|
|
11
|
+
To install into Claude you have to add JSON to the `claude_desktop_config.json`
|
|
12
|
+
|
|
13
|
+
An official tutorial can found here: https://modelcontextprotocol.io/quickstart/user#2-add-the-filesystem-mcp-server
|
|
14
|
+
|
|
15
|
+
To add our MCP, add the following JSON (be sure to change the path and FILESCOM_API_KEY value)
|
|
16
|
+
|
|
17
|
+
NOTE: This version assumes you are running from source. Once we have PyPi publishing this README will have them version as well.
|
|
18
|
+
|
|
19
|
+
### uv Required
|
|
20
|
+
|
|
21
|
+
These examples requires `uv` which is a popular modern environment manager for running isolated python tools. Installation is out of scope of this README.
|
|
22
|
+
|
|
23
|
+
### Claude Config - STDIO
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
{
|
|
27
|
+
"mcpServers": {
|
|
28
|
+
"files_com_mcp": {
|
|
29
|
+
"type": "stdio",
|
|
30
|
+
"command": "uv",
|
|
31
|
+
"args": [
|
|
32
|
+
"--directory",
|
|
33
|
+
"/path/to/folder-containing-files_com_mcp",
|
|
34
|
+
"run",
|
|
35
|
+
"-m",
|
|
36
|
+
"files_com_mcp"
|
|
37
|
+
],
|
|
38
|
+
"env": {
|
|
39
|
+
"FILES_COM_API_KEY": "CHangeME"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Development
|
|
47
|
+
|
|
48
|
+
While our MCP works well out-of-the-box, some power users find value in modifying MCP code to suit their unique needs. For those power users, it is recommended to use STDIO mode. Upload and Download tools rely on the file system where the MCP is running.
|
|
49
|
+
|
|
50
|
+
To test LLM tools we recommend a popular command-line program called `inspector`. This will start a WebUI on a local port, the output of the command will give you the link to the inspector GUI.
|
|
51
|
+
Ex: http://127.0.0.1:6274
|
|
52
|
+
|
|
53
|
+
## Develoment - STDIO
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
FILESCOM_API_KEY="dummyKey" npx @modelcontextprotocol/inspector uv run -m files_com_mcp
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Development - SSE
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
FILESCOM_API_KEY="dummyKey" uv run -m files_com_mcp --mode server --port 12345
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Launch the inspector
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
npx @modelcontextprotocol/inspector
|
|
69
|
+
```
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import os
|
|
3
|
+
import files_sdk
|
|
4
|
+
from files_com_mcp.server import run_stdio, run_server
|
|
5
|
+
|
|
6
|
+
def main():
|
|
7
|
+
parser = argparse.ArgumentParser(description="Run MCP server")
|
|
8
|
+
|
|
9
|
+
parser.add_argument(
|
|
10
|
+
"--mode", choices=["stdio", "server"], default="stdio",
|
|
11
|
+
help="Transport mode: stdio or server (HTTP)"
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
parser.add_argument(
|
|
15
|
+
"--port", type=int, default=8000,
|
|
16
|
+
help="Port to use in server mode"
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
args = parser.parse_args()
|
|
20
|
+
|
|
21
|
+
if args.mode == "stdio":
|
|
22
|
+
run_stdio()
|
|
23
|
+
elif args.mode == "server":
|
|
24
|
+
run_server(port=args.port)
|
|
25
|
+
|
|
26
|
+
if __name__ == "__main__":
|
|
27
|
+
# For pointing to mock server for testing
|
|
28
|
+
if os.getenv("FILES_COM_BASE_URL"):
|
|
29
|
+
files_sdk.base_url = os.getenv("FILES_COM_BASE_URL")
|
|
30
|
+
|
|
31
|
+
main()
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
|
|
3
|
+
async def check_platform_status() -> str:
|
|
4
|
+
"""Check Files.com platform status at status.files.com."""
|
|
5
|
+
url = "https://status.files.com/api/v2/status.json"
|
|
6
|
+
try:
|
|
7
|
+
response = requests.get(url)
|
|
8
|
+
if response.status_code == 200:
|
|
9
|
+
return response.json().get('status', {}).get('description', 'Error processing the status page')
|
|
10
|
+
else:
|
|
11
|
+
return "Error connecting to status page"
|
|
12
|
+
except requests.exceptions.RequestException:
|
|
13
|
+
return "Error connecting to status page"
|
|
14
|
+
|
|
15
|
+
def register_tools(mcp):
|
|
16
|
+
@mcp.tool()
|
|
17
|
+
async def check_platform_status_tool() -> str:
|
|
18
|
+
return await check_platform_status()
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from fastmcp import Context
|
|
3
|
+
import files_sdk
|
|
4
|
+
import files_sdk.error
|
|
5
|
+
|
|
6
|
+
async def download_file_to_local(context: Context, remote_path: str, local_path: str) -> str:
|
|
7
|
+
"""Download a file from my Files.com site. Specify the remote path of the file to download and a local path to save the file at.
|
|
8
|
+
|
|
9
|
+
Args:
|
|
10
|
+
remote_path: The full path on my Files.com site of the file to be downloaded.
|
|
11
|
+
local_path: The full path on my local system to save the downloaded file to. Must be a path that can be written to. When in doubt, use the `$HOME/Downloads` folder, or the `/tmp/` folder, as the destination for the downloaded file.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
try:
|
|
15
|
+
options = {"api_key": context.request_context.session._files_com_api_key}
|
|
16
|
+
|
|
17
|
+
files_sdk.file.download_file(remote_path, local_path, options)
|
|
18
|
+
return f"File downloaded successfully to: {os.path.abspath(local_path)}"
|
|
19
|
+
|
|
20
|
+
except files_sdk.error.NotAuthenticatedError as err:
|
|
21
|
+
return f"Authentication Error: {err}"
|
|
22
|
+
except files_sdk.error.Error as err:
|
|
23
|
+
return f"Files.com Error: {err}"
|
|
24
|
+
except Exception as ex:
|
|
25
|
+
return f"General Exception: {ex}"
|
|
26
|
+
|
|
27
|
+
async def upload_file_from_local(context: Context, local_path: str, remote_path: str) -> str:
|
|
28
|
+
"""Upload a file to my Files.com site. Specify the local path of the file to upload and a remote path to save the file at.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
local_path: The full path on my local system of the file to be uploaded.
|
|
32
|
+
remote_path: The full path on my Files.com site for the file to be uploaded to.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
try:
|
|
36
|
+
options = {"api_key": context.request_context.session._files_com_api_key}
|
|
37
|
+
params = {}
|
|
38
|
+
|
|
39
|
+
# Smart Default(s)
|
|
40
|
+
params["mkdir_parents"] = True
|
|
41
|
+
|
|
42
|
+
files_sdk.file.upload_file(local_path, remote_path, options, params)
|
|
43
|
+
return f"File uploaded successfully from: {os.path.abspath(local_path)}"
|
|
44
|
+
|
|
45
|
+
except files_sdk.error.NotAuthenticatedError as err:
|
|
46
|
+
return f"Authentication Error: {err}"
|
|
47
|
+
except files_sdk.error.Error as err:
|
|
48
|
+
return f"Files.com Error: {err}"
|
|
49
|
+
except Exception as ex:
|
|
50
|
+
return f"General Exception: {ex}"
|
|
51
|
+
|
|
52
|
+
def register_tools(mcp):
|
|
53
|
+
@mcp.tool()
|
|
54
|
+
async def download_file_to_local_tool(context: Context, remote_path: str, local_path: str) -> str:
|
|
55
|
+
return await download_file_to_local(context, remote_path, local_path)
|
|
56
|
+
|
|
57
|
+
@mcp.tool()
|
|
58
|
+
async def upload_file_from_local_tool(context: Context, local_path: str, remote_path: str, ) -> str:
|
|
59
|
+
return await upload_file_from_local(context, local_path, remote_path)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
tool_list = ["bundle", "bundle_download", "bundle_notification", "bundle_recipient", "bundle_registration", "file", "folder", "group", "user", "automation", "history", "permission", "remote_server"]
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
from fastmcp import Context
|
|
2
|
+
from files_com_mcp.utils import object_list_to_markdown_table
|
|
3
|
+
import files_sdk
|
|
4
|
+
import files_sdk.error
|
|
5
|
+
|
|
6
|
+
async def list_automation(context: Context) -> str:
|
|
7
|
+
"""List Automations"""
|
|
8
|
+
|
|
9
|
+
try:
|
|
10
|
+
options = {"api_key": context.request_context.session._files_com_api_key}
|
|
11
|
+
params = {}
|
|
12
|
+
|
|
13
|
+
retval = files_sdk.automation.list(params, options)
|
|
14
|
+
retval = [item for item in retval.auto_paging_iter()]
|
|
15
|
+
if not retval:
|
|
16
|
+
return "No automations found."
|
|
17
|
+
|
|
18
|
+
markdown_list = object_list_to_markdown_table(retval, ["id", "always_overwrite_size_matching_files", "automation", "deleted", "description", "destination_replace_from", "destination_replace_to", "destinations", "disabled", "exclude_pattern", "import_urls", "flatten_destination_structure", "group_ids", "ignore_locked_folders", "interval", "last_modified_at", "legacy_folder_matching", "name", "overwrite_files", "path", "path_time_zone", "recurring_day", "retry_on_failure_interval_in_minutes", "retry_on_failure_number_of_attempts", "schedule", "human_readable_schedule", "schedule_days_of_week", "schedule_times_of_day", "schedule_time_zone", "source", "sync_ids", "trigger_actions", "trigger", "user_id", "user_ids", "value", "webhook_url"])
|
|
19
|
+
return f"Automation Response:\n{markdown_list}"
|
|
20
|
+
except files_sdk.error.NotAuthenticatedError as err:
|
|
21
|
+
return f"Authentication Error: {err}"
|
|
22
|
+
except files_sdk.error.Error as err:
|
|
23
|
+
return f"Files.com Error: {err}"
|
|
24
|
+
except Exception as ex:
|
|
25
|
+
return f"General Exception: {ex}"
|
|
26
|
+
|
|
27
|
+
async def find_automation(context: Context, id: int | None = None) -> str:
|
|
28
|
+
"""Show Automation
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
id: Automation ID.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
try:
|
|
35
|
+
options = {"api_key": context.request_context.session._files_com_api_key}
|
|
36
|
+
params = {}
|
|
37
|
+
if id is None:
|
|
38
|
+
return "Missing required parameter: id"
|
|
39
|
+
params["id"] = id
|
|
40
|
+
|
|
41
|
+
retval = files_sdk.automation.find(id, params, options)
|
|
42
|
+
retval = [retval]
|
|
43
|
+
|
|
44
|
+
markdown_list = object_list_to_markdown_table(retval, ["id", "always_overwrite_size_matching_files", "automation", "deleted", "description", "destination_replace_from", "destination_replace_to", "destinations", "disabled", "exclude_pattern", "import_urls", "flatten_destination_structure", "group_ids", "ignore_locked_folders", "interval", "last_modified_at", "legacy_folder_matching", "name", "overwrite_files", "path", "path_time_zone", "recurring_day", "retry_on_failure_interval_in_minutes", "retry_on_failure_number_of_attempts", "schedule", "human_readable_schedule", "schedule_days_of_week", "schedule_times_of_day", "schedule_time_zone", "source", "sync_ids", "trigger_actions", "trigger", "user_id", "user_ids", "value", "webhook_url"])
|
|
45
|
+
return f"Automation Response:\n{markdown_list}"
|
|
46
|
+
except files_sdk.error.NotAuthenticatedError as err:
|
|
47
|
+
return f"Authentication Error: {err}"
|
|
48
|
+
except files_sdk.error.Error as err:
|
|
49
|
+
return f"Files.com Error: {err}"
|
|
50
|
+
except Exception as ex:
|
|
51
|
+
return f"General Exception: {ex}"
|
|
52
|
+
|
|
53
|
+
async def create_automation(context: Context, automation: str | None = None) -> str:
|
|
54
|
+
"""Create Automation
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
automation: Automation type
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
try:
|
|
61
|
+
options = {"api_key": context.request_context.session._files_com_api_key}
|
|
62
|
+
params = {}
|
|
63
|
+
if automation is None:
|
|
64
|
+
return "Missing required parameter: automation"
|
|
65
|
+
params["automation"] = automation
|
|
66
|
+
|
|
67
|
+
retval = files_sdk.automation.create(params, options)
|
|
68
|
+
retval = [retval]
|
|
69
|
+
|
|
70
|
+
markdown_list = object_list_to_markdown_table(retval, ["id", "always_overwrite_size_matching_files", "automation", "deleted", "description", "destination_replace_from", "destination_replace_to", "destinations", "disabled", "exclude_pattern", "import_urls", "flatten_destination_structure", "group_ids", "ignore_locked_folders", "interval", "last_modified_at", "legacy_folder_matching", "name", "overwrite_files", "path", "path_time_zone", "recurring_day", "retry_on_failure_interval_in_minutes", "retry_on_failure_number_of_attempts", "schedule", "human_readable_schedule", "schedule_days_of_week", "schedule_times_of_day", "schedule_time_zone", "source", "sync_ids", "trigger_actions", "trigger", "user_id", "user_ids", "value", "webhook_url"])
|
|
71
|
+
return f"Automation Response:\n{markdown_list}"
|
|
72
|
+
except files_sdk.error.NotAuthenticatedError as err:
|
|
73
|
+
return f"Authentication Error: {err}"
|
|
74
|
+
except files_sdk.error.Error as err:
|
|
75
|
+
return f"Files.com Error: {err}"
|
|
76
|
+
except Exception as ex:
|
|
77
|
+
return f"General Exception: {ex}"
|
|
78
|
+
|
|
79
|
+
async def update_automation(context: Context, id: int | None = None) -> str:
|
|
80
|
+
"""Update Automation
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
id: Automation ID.
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
try:
|
|
87
|
+
options = {"api_key": context.request_context.session._files_com_api_key}
|
|
88
|
+
params = {}
|
|
89
|
+
if id is None:
|
|
90
|
+
return "Missing required parameter: id"
|
|
91
|
+
params["id"] = id
|
|
92
|
+
|
|
93
|
+
retval = files_sdk.automation.update(id, params, options)
|
|
94
|
+
retval = [retval]
|
|
95
|
+
|
|
96
|
+
markdown_list = object_list_to_markdown_table(retval, ["id", "always_overwrite_size_matching_files", "automation", "deleted", "description", "destination_replace_from", "destination_replace_to", "destinations", "disabled", "exclude_pattern", "import_urls", "flatten_destination_structure", "group_ids", "ignore_locked_folders", "interval", "last_modified_at", "legacy_folder_matching", "name", "overwrite_files", "path", "path_time_zone", "recurring_day", "retry_on_failure_interval_in_minutes", "retry_on_failure_number_of_attempts", "schedule", "human_readable_schedule", "schedule_days_of_week", "schedule_times_of_day", "schedule_time_zone", "source", "sync_ids", "trigger_actions", "trigger", "user_id", "user_ids", "value", "webhook_url"])
|
|
97
|
+
return f"Automation Response:\n{markdown_list}"
|
|
98
|
+
except files_sdk.error.NotAuthenticatedError as err:
|
|
99
|
+
return f"Authentication Error: {err}"
|
|
100
|
+
except files_sdk.error.Error as err:
|
|
101
|
+
return f"Files.com Error: {err}"
|
|
102
|
+
except Exception as ex:
|
|
103
|
+
return f"General Exception: {ex}"
|
|
104
|
+
|
|
105
|
+
async def delete_automation(context: Context, id: int | None = None) -> str:
|
|
106
|
+
"""Delete Automation
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
id: Automation ID.
|
|
110
|
+
"""
|
|
111
|
+
|
|
112
|
+
try:
|
|
113
|
+
options = {"api_key": context.request_context.session._files_com_api_key}
|
|
114
|
+
params = {}
|
|
115
|
+
if id is None:
|
|
116
|
+
return "Missing required parameter: id"
|
|
117
|
+
params["id"] = id
|
|
118
|
+
|
|
119
|
+
retval = files_sdk.automation.delete(id, params, options)
|
|
120
|
+
retval = [retval]
|
|
121
|
+
|
|
122
|
+
markdown_list = object_list_to_markdown_table(retval, ["id", "always_overwrite_size_matching_files", "automation", "deleted", "description", "destination_replace_from", "destination_replace_to", "destinations", "disabled", "exclude_pattern", "import_urls", "flatten_destination_structure", "group_ids", "ignore_locked_folders", "interval", "last_modified_at", "legacy_folder_matching", "name", "overwrite_files", "path", "path_time_zone", "recurring_day", "retry_on_failure_interval_in_minutes", "retry_on_failure_number_of_attempts", "schedule", "human_readable_schedule", "schedule_days_of_week", "schedule_times_of_day", "schedule_time_zone", "source", "sync_ids", "trigger_actions", "trigger", "user_id", "user_ids", "value", "webhook_url"])
|
|
123
|
+
return f"Automation Response:\n{markdown_list}"
|
|
124
|
+
except files_sdk.error.NotAuthenticatedError as err:
|
|
125
|
+
return f"Authentication Error: {err}"
|
|
126
|
+
except files_sdk.error.Error as err:
|
|
127
|
+
return f"Files.com Error: {err}"
|
|
128
|
+
except Exception as ex:
|
|
129
|
+
return f"General Exception: {ex}"
|
|
130
|
+
|
|
131
|
+
def register_tools(mcp):
|
|
132
|
+
@mcp.tool()
|
|
133
|
+
async def list_automation_tool(context: Context) -> str:
|
|
134
|
+
return await list_automation(context)
|
|
135
|
+
|
|
136
|
+
@mcp.tool()
|
|
137
|
+
async def find_automation_tool(context: Context, id: int | None = None) -> str:
|
|
138
|
+
return await find_automation(context, id)
|
|
139
|
+
|
|
140
|
+
@mcp.tool()
|
|
141
|
+
async def create_automation_tool(context: Context, automation: str | None = None) -> str:
|
|
142
|
+
return await create_automation(context, automation)
|
|
143
|
+
|
|
144
|
+
@mcp.tool()
|
|
145
|
+
async def update_automation_tool(context: Context, id: int | None = None) -> str:
|
|
146
|
+
return await update_automation(context, id)
|
|
147
|
+
|
|
148
|
+
@mcp.tool()
|
|
149
|
+
async def delete_automation_tool(context: Context, id: int | None = None) -> str:
|
|
150
|
+
return await delete_automation(context, id)
|
|
151
|
+
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
from fastmcp import Context
|
|
2
|
+
from files_com_mcp.utils import object_list_to_markdown_table
|
|
3
|
+
import files_sdk
|
|
4
|
+
import files_sdk.error
|
|
5
|
+
|
|
6
|
+
async def list_bundle(context: Context) -> str:
|
|
7
|
+
"""List Bundles"""
|
|
8
|
+
|
|
9
|
+
try:
|
|
10
|
+
options = {"api_key": context.request_context.session._files_com_api_key}
|
|
11
|
+
params = {}
|
|
12
|
+
|
|
13
|
+
retval = files_sdk.bundle.list(params, options)
|
|
14
|
+
retval = [item for item in retval.auto_paging_iter()]
|
|
15
|
+
if not retval:
|
|
16
|
+
return "No bundles found."
|
|
17
|
+
|
|
18
|
+
markdown_list = object_list_to_markdown_table(retval, ["id", "paths", "password", "expires_at", "max_uses", "description", "note", "require_registration"])
|
|
19
|
+
return f"Bundle Response:\n{markdown_list}"
|
|
20
|
+
except files_sdk.error.NotAuthenticatedError as err:
|
|
21
|
+
return f"Authentication Error: {err}"
|
|
22
|
+
except files_sdk.error.Error as err:
|
|
23
|
+
return f"Files.com Error: {err}"
|
|
24
|
+
except Exception as ex:
|
|
25
|
+
return f"General Exception: {ex}"
|
|
26
|
+
|
|
27
|
+
async def find_bundle(context: Context, id: int | None = None) -> str:
|
|
28
|
+
"""Show Bundle
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
id: Bundle ID.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
try:
|
|
35
|
+
options = {"api_key": context.request_context.session._files_com_api_key}
|
|
36
|
+
params = {}
|
|
37
|
+
if id is None:
|
|
38
|
+
return "Missing required parameter: id"
|
|
39
|
+
params["id"] = id
|
|
40
|
+
|
|
41
|
+
retval = files_sdk.bundle.find(id, params, options)
|
|
42
|
+
retval = [retval]
|
|
43
|
+
|
|
44
|
+
markdown_list = object_list_to_markdown_table(retval, ["id", "paths", "password", "expires_at", "max_uses", "description", "note", "require_registration"])
|
|
45
|
+
return f"Bundle Response:\n{markdown_list}"
|
|
46
|
+
except files_sdk.error.NotAuthenticatedError as err:
|
|
47
|
+
return f"Authentication Error: {err}"
|
|
48
|
+
except files_sdk.error.Error as err:
|
|
49
|
+
return f"Files.com Error: {err}"
|
|
50
|
+
except Exception as ex:
|
|
51
|
+
return f"General Exception: {ex}"
|
|
52
|
+
|
|
53
|
+
async def create_bundle(context: Context, paths: list | None = None, password: str | None = None, expires_at: str | None = None, max_uses: int | None = None, description: str | None = None, note: str | None = None, require_registration: bool | None = None) -> str:
|
|
54
|
+
"""Create Bundle
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
paths: A list of paths to include in this bundle.
|
|
58
|
+
password: Password for this bundle.
|
|
59
|
+
expires_at: Bundle expiration date/time
|
|
60
|
+
max_uses: Maximum number of times bundle can be accessed
|
|
61
|
+
description: Public description
|
|
62
|
+
note: Bundle internal note
|
|
63
|
+
require_registration: Show a registration page that captures the downloader's name and email address?
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
try:
|
|
67
|
+
options = {"api_key": context.request_context.session._files_com_api_key}
|
|
68
|
+
params = {}
|
|
69
|
+
if paths is None:
|
|
70
|
+
return "Missing required parameter: paths"
|
|
71
|
+
params["paths"] = paths
|
|
72
|
+
if password is not None:
|
|
73
|
+
params["password"] = password
|
|
74
|
+
if expires_at is not None:
|
|
75
|
+
params["expires_at"] = expires_at
|
|
76
|
+
if max_uses is not None:
|
|
77
|
+
params["max_uses"] = max_uses
|
|
78
|
+
if description is not None:
|
|
79
|
+
params["description"] = description
|
|
80
|
+
if note is not None:
|
|
81
|
+
params["note"] = note
|
|
82
|
+
if require_registration is not None:
|
|
83
|
+
params["require_registration"] = require_registration
|
|
84
|
+
|
|
85
|
+
# Smart Default(s)
|
|
86
|
+
params["permissions"] = "read"
|
|
87
|
+
|
|
88
|
+
retval = files_sdk.bundle.create(params, options)
|
|
89
|
+
retval = [retval]
|
|
90
|
+
|
|
91
|
+
markdown_list = object_list_to_markdown_table(retval, ["id", "paths", "password", "expires_at", "max_uses", "description", "note", "require_registration"])
|
|
92
|
+
return f"Bundle Response:\n{markdown_list}"
|
|
93
|
+
except files_sdk.error.NotAuthenticatedError as err:
|
|
94
|
+
return f"Authentication Error: {err}"
|
|
95
|
+
except files_sdk.error.Error as err:
|
|
96
|
+
return f"Files.com Error: {err}"
|
|
97
|
+
except Exception as ex:
|
|
98
|
+
return f"General Exception: {ex}"
|
|
99
|
+
|
|
100
|
+
async def update_bundle(context: Context, id: int | None = None, expires_at: str | None = None) -> str:
|
|
101
|
+
"""Update Bundle
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
id: Bundle ID.
|
|
105
|
+
expires_at: Bundle expiration date/time
|
|
106
|
+
"""
|
|
107
|
+
|
|
108
|
+
try:
|
|
109
|
+
options = {"api_key": context.request_context.session._files_com_api_key}
|
|
110
|
+
params = {}
|
|
111
|
+
if id is None:
|
|
112
|
+
return "Missing required parameter: id"
|
|
113
|
+
params["id"] = id
|
|
114
|
+
if expires_at is not None:
|
|
115
|
+
params["expires_at"] = expires_at
|
|
116
|
+
|
|
117
|
+
retval = files_sdk.bundle.update(id, params, options)
|
|
118
|
+
retval = [retval]
|
|
119
|
+
|
|
120
|
+
markdown_list = object_list_to_markdown_table(retval, ["id", "paths", "password", "expires_at", "max_uses", "description", "note", "require_registration"])
|
|
121
|
+
return f"Bundle Response:\n{markdown_list}"
|
|
122
|
+
except files_sdk.error.NotAuthenticatedError as err:
|
|
123
|
+
return f"Authentication Error: {err}"
|
|
124
|
+
except files_sdk.error.Error as err:
|
|
125
|
+
return f"Files.com Error: {err}"
|
|
126
|
+
except Exception as ex:
|
|
127
|
+
return f"General Exception: {ex}"
|
|
128
|
+
|
|
129
|
+
async def delete_bundle(context: Context, id: int | None = None) -> str:
|
|
130
|
+
"""Delete Bundle
|
|
131
|
+
|
|
132
|
+
Args:
|
|
133
|
+
id: Bundle ID.
|
|
134
|
+
"""
|
|
135
|
+
|
|
136
|
+
try:
|
|
137
|
+
options = {"api_key": context.request_context.session._files_com_api_key}
|
|
138
|
+
params = {}
|
|
139
|
+
if id is None:
|
|
140
|
+
return "Missing required parameter: id"
|
|
141
|
+
params["id"] = id
|
|
142
|
+
|
|
143
|
+
retval = files_sdk.bundle.delete(id, params, options)
|
|
144
|
+
retval = [retval]
|
|
145
|
+
|
|
146
|
+
markdown_list = object_list_to_markdown_table(retval, ["id", "paths", "password", "expires_at", "max_uses", "description", "note", "require_registration"])
|
|
147
|
+
return f"Bundle Response:\n{markdown_list}"
|
|
148
|
+
except files_sdk.error.NotAuthenticatedError as err:
|
|
149
|
+
return f"Authentication Error: {err}"
|
|
150
|
+
except files_sdk.error.Error as err:
|
|
151
|
+
return f"Files.com Error: {err}"
|
|
152
|
+
except Exception as ex:
|
|
153
|
+
return f"General Exception: {ex}"
|
|
154
|
+
|
|
155
|
+
def register_tools(mcp):
|
|
156
|
+
@mcp.tool()
|
|
157
|
+
async def list_bundle_tool(context: Context) -> str:
|
|
158
|
+
return await list_bundle(context)
|
|
159
|
+
|
|
160
|
+
@mcp.tool()
|
|
161
|
+
async def find_bundle_tool(context: Context, id: int | None = None) -> str:
|
|
162
|
+
return await find_bundle(context, id)
|
|
163
|
+
|
|
164
|
+
@mcp.tool()
|
|
165
|
+
async def create_bundle_tool(context: Context, paths: list | None = None, password: str | None = None, expires_at: str | None = None, max_uses: int | None = None, description: str | None = None, note: str | None = None, require_registration: bool | None = None) -> str:
|
|
166
|
+
return await create_bundle(context, paths, password, expires_at, max_uses, description, note, require_registration)
|
|
167
|
+
|
|
168
|
+
@mcp.tool()
|
|
169
|
+
async def update_bundle_tool(context: Context, id: int | None = None, expires_at: str | None = None) -> str:
|
|
170
|
+
return await update_bundle(context, id, expires_at)
|
|
171
|
+
|
|
172
|
+
@mcp.tool()
|
|
173
|
+
async def delete_bundle_tool(context: Context, id: int | None = None) -> str:
|
|
174
|
+
return await delete_bundle(context, id)
|
|
175
|
+
|