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 changed (35) hide show
  1. files_com_mcp-1.0/LICENSE +21 -0
  2. files_com_mcp-1.0/PKG-INFO +84 -0
  3. files_com_mcp-1.0/README.md +69 -0
  4. files_com_mcp-1.0/files_com_mcp/__init__.py +3 -0
  5. files_com_mcp-1.0/files_com_mcp/__main__.py +31 -0
  6. files_com_mcp-1.0/files_com_mcp/authored_tools/__init__.py +4 -0
  7. files_com_mcp-1.0/files_com_mcp/authored_tools/check_platform_status.py +18 -0
  8. files_com_mcp-1.0/files_com_mcp/authored_tools/debug.py +8 -0
  9. files_com_mcp-1.0/files_com_mcp/authored_tools/local_transfer.py +59 -0
  10. files_com_mcp-1.0/files_com_mcp/generated_tools/__init__.py +1 -0
  11. files_com_mcp-1.0/files_com_mcp/generated_tools/automation.py +151 -0
  12. files_com_mcp-1.0/files_com_mcp/generated_tools/bundle.py +175 -0
  13. files_com_mcp-1.0/files_com_mcp/generated_tools/bundle_download.py +37 -0
  14. files_com_mcp-1.0/files_com_mcp/generated_tools/bundle_notification.py +166 -0
  15. files_com_mcp-1.0/files_com_mcp/generated_tools/bundle_recipient.py +84 -0
  16. files_com_mcp-1.0/files_com_mcp/generated_tools/bundle_registration.py +37 -0
  17. files_com_mcp-1.0/files_com_mcp/generated_tools/file.py +134 -0
  18. files_com_mcp-1.0/files_com_mcp/generated_tools/folder.py +71 -0
  19. files_com_mcp-1.0/files_com_mcp/generated_tools/group.py +172 -0
  20. files_com_mcp-1.0/files_com_mcp/generated_tools/history.py +152 -0
  21. files_com_mcp-1.0/files_com_mcp/generated_tools/permission.py +112 -0
  22. files_com_mcp-1.0/files_com_mcp/generated_tools/remote_server.py +61 -0
  23. files_com_mcp-1.0/files_com_mcp/generated_tools/user.py +238 -0
  24. files_com_mcp-1.0/files_com_mcp/patches/__init__.py +1 -0
  25. files_com_mcp-1.0/files_com_mcp/patches/fastmcp_settings_patch.py +12 -0
  26. files_com_mcp-1.0/files_com_mcp/server.py +31 -0
  27. files_com_mcp-1.0/files_com_mcp/utils.py +25 -0
  28. files_com_mcp-1.0/files_com_mcp.egg-info/PKG-INFO +84 -0
  29. files_com_mcp-1.0/files_com_mcp.egg-info/SOURCES.txt +33 -0
  30. files_com_mcp-1.0/files_com_mcp.egg-info/dependency_links.txt +1 -0
  31. files_com_mcp-1.0/files_com_mcp.egg-info/requires.txt +5 -0
  32. files_com_mcp-1.0/files_com_mcp.egg-info/top_level.txt +3 -0
  33. files_com_mcp-1.0/pyproject.toml +40 -0
  34. files_com_mcp-1.0/setup.cfg +4 -0
  35. 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,3 @@
1
+ from . import utils # noqa: F401
2
+
3
+ __version__ = "0.1.0"
@@ -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,4 @@
1
+ # List of tool modules to be loaded dynamically
2
+ tool_list = ["local_transfer"]
3
+ # Enable these for debugging and testing
4
+ #tool_list = tool_list + ["check_platform_status", "debug"]
@@ -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,8 @@
1
+ async def hello_world() -> str:
2
+ """Files.com MCP Debugging Hello World function."""
3
+ return "Hello World"
4
+
5
+ def register_tools(mcp):
6
+ @mcp.tool()
7
+ async def hello_world_tool() -> str:
8
+ return await hello_world()
@@ -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
+