Spaces:
Sleeping
Sleeping
File size: 8,185 Bytes
2f99641 25d29c4 2f99641 25d29c4 2f99641 25d29c4 2f99641 25d29c4 2f99641 25d29c4 2f99641 25d29c4 2f99641 25d29c4 2f99641 25d29c4 2f99641 a0b9719 2f99641 f36616f 7d01915 e903cc3 f36616f f4206a8 2f99641 a0b9719 2f99641 4f3aa05 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
import gradio as gr
from pathlib import Path
import traceback
from filesystem_access import FilesystemAccess
import os
fs = FilesystemAccess(os.getenv("FILES_DIR"))
allow_writes = os.getenv("ALLOW_EDITING") == "true" or os.getenv("ALLOW_EDITING") == "1"
def safe_exec(func, *args, **kwargs):
try:
return func(*args, **kwargs)
except FileNotFoundError as e:
print(f"Not found: {str(e)}")
return f"Error: Not found"
except FileExistsError as e:
print(f"Already exists: {str(e)}")
return f"Error: Already exists"
except Exception as e:
print(f"Error: {str(e)}\n{traceback.format_exc()}")
return f"Error"
def read_file(path):
"""
Read the contents of a file at the given path.
Args:
path (str): The path to the file to read.
Returns:
str: The contents of the file, or an error message if not found.
"""
return safe_exec(fs.read_file, path)
def read_multiple_files(paths):
"""
Read the contents of multiple files specified by a comma-separated list of paths.
Args:
paths (str): Comma-separated file paths to read.
Returns:
str: The concatenated contents of all files, or error messages for files that could not be read.
"""
path_list = [p.strip() for p in paths.split(',') if p.strip()]
file_contents = []
try:
for path in path_list:
try:
file_content = fs.read_file(path)
file_contents.append(f"{path}:\n{file_content}\n")
except Exception as e:
file_contents.append(f"{path}:Error - Could not read file")
return "\n---\n".join(file_contents)
except Exception as e:
print(f"Error: {str(e)}\n{traceback.format_exc()}")
return f"Error"
def write_file(path, content):
"""
Write content to a file at the given path.
Args:
path (str): The path to the file to write.
content (str): The content to write to the file.
Returns:
str: Success message or error message if the write fails.
"""
return safe_exec(fs.write_file, path, content) or "File written successfully."
def create_directory(path):
"""
Create a directory at the given path, including any necessary parent directories.
Args:
path (str): The directory path to create.
Returns:
str: Success message or error message if creation fails.
"""
return safe_exec(fs.create_directory, path) or "Directory ensured."
def list_directory(path):
"""
List the contents of a directory at the given path.
Args:
path (str): The directory path to list.
Returns:
str: Newline-separated list of directory contents, or error message if listing fails.
"""
return '\n'.join(safe_exec(fs.list_directory, path))
def move_file(source, destination):
"""
Move a file from source to destination path.
Args:
source (str): The source file path.
destination (str): The destination file path.
Returns:
str: Success message or error message if move fails.
"""
return safe_exec(fs.move_file, source, destination) or "Move successful."
def search_files(path, pattern, exclude):
"""
Search for files in a directory matching a pattern, excluding specified patterns.
Args:
path (str): The directory path to search in.
pattern (str): The glob pattern to match files.
exclude (str): Comma-separated patterns to exclude from results.
Returns:
str: Newline-separated list of matching file paths, or error message if search fails.
"""
exclude_list = [e.strip() for e in exclude.split(',') if e.strip()]
return '\n'.join(safe_exec(fs.search_files, path, pattern, exclude_list))
def directory_tree(path):
"""
Get a tree representation of the directory at the given path.
Args:
path (str): The directory path to show as a tree.
Returns:
str: The directory tree as a string, or error message if operation fails.
"""
return safe_exec(fs.directory_tree, path)
def recursive_list(path):
"""
Get a recursive list of the Motion Canvas documentation directory at the given path.
Args:
path (str): The documentation directory path to show as a recursive list.
Returns:
str: The documentation directory recursive list as a string, or error message if operation fails.
"""
return safe_exec(fs.recursive_list, path)
with gr.Blocks() as demo:
gr.Markdown("""
# Filesystem MCP Server
This is a simple MCP server based on Gradio that allows you to read and write files to a local directory. Please note that this code is a proof of concept and not meant for production.
You can configure whether you want to allow editing the files by setting the environment variable `ALLOW_EDITING`. The files reside in `/app/files`. Using Docker, you can mount external directories as well.
The API is a simpler version of https://github.com/modelcontextprotocol/servers/tree/main/src/filesystem .
Important: The files on the public Hugging Face Space are shared. This means that anyone can read and write to the files. You can spawn the MCP server locally or duplicate the space.
""")
gr.Markdown(" You can find a demo video here: https://youtu.be/9YiiNpxgnaU ")
with gr.Tab("Read File"):
path = gr.Textbox(label="Path", value="index.md")
output = gr.Textbox(label="File Contents")
btn = gr.Button("Read")
btn.click(fn=read_file, inputs=path, outputs=output)
with gr.Tab("Read Multiple Files"):
paths = gr.Textbox(label="Comma-separated Paths", value="index.md,index.html")
output = gr.Textbox(label="Results")
btn = gr.Button("Read")
btn.click(fn=read_multiple_files, inputs=paths, outputs=output)
with gr.Tab("List Directory"):
path = gr.Textbox(label="Directory Path", value=".")
output = gr.Textbox(label="Contents")
btn = gr.Button("List")
btn.click(fn=list_directory, inputs=path, outputs=output)
with gr.Tab("Directory Tree"):
path = gr.Textbox(label="Directory Path", value=".")
output = gr.Textbox(label="Contents")
btn = gr.Button("Show Tree")
btn.click(fn=directory_tree, inputs=path, outputs=output)
with gr.Tab("Recursive List"):
path = gr.Textbox(label="Directory Path", value=".")
output = gr.Textbox(label="Contents")
btn = gr.Button("Show Recursive List")
btn.click(fn=recursive_list, inputs=path, outputs=output)
with gr.Tab("Search Files"):
path = gr.Textbox(label="Search Directory", value=".")
pattern = gr.Textbox(label="Pattern", value="*.html")
exclude = gr.Textbox(label="Exclude Patterns (comma-separated)", value="*.md")
output = gr.Textbox(label="Matches")
btn = gr.Button("Search")
btn.click(fn=search_files, inputs=[path, pattern, exclude], outputs=output)
if allow_writes:
with gr.Tab("Write File"):
path = gr.Textbox(label="Path", value="index.html")
content = gr.Textbox(label="Content", lines=10, value="<html><body><h1>Hello World</h1></body></html>")
output = gr.Textbox(label="Status")
btn = gr.Button("Write")
btn.click(fn=write_file, inputs=[path, content], outputs=output)
with gr.Tab("Create Directory"):
path = gr.Textbox(label="Directory Path", value="test")
output = gr.Textbox(label="Status")
btn = gr.Button("Create")
btn.click(fn=create_directory, inputs=path, outputs=output)
with gr.Tab("Move File"):
source = gr.Textbox(label="Source Path", value="index.html")
destination = gr.Textbox(label="Destination Path", value="test/index.html")
output = gr.Textbox(label="Status")
btn = gr.Button("Move")
btn.click(fn=move_file, inputs=[source, destination], outputs=output)
if __name__ == "__main__":
demo.launch(mcp_server=True) |