ChrisSacrumCor's picture
Create app.py
5c0f36f verified
raw
history blame
7.95 kB
"""
Linux MCP Server using Gradio's built-in MCP support.
This creates both the MCP server and a web interface for tool management.
"""
import gradio as gr
import os
import sys
from pathlib import Path
# Add project root to path
project_root = Path(__file__).parent
sys.path.insert(0, str(project_root))
# Import our tools
from tools.linux_tools import (
add_user,
create_file,
change_permission,
run_safe_command
)
from shared.config import config
import logging
# Set up logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def create_linux_mcp_server():
"""
Create the Linux MCP server with Gradio.
Gradio automatically converts @gr.tool functions into MCP tools.
"""
# Define the tools list for Gradio
tools = [
run_safe_command, # Safe operations (low risk)
add_user, # Sensitive operations (high risk)
create_file, # Sensitive operations (high risk)
change_permission # Sensitive operations (high risk)
]
# Create the MCP server interface
with gr.Blocks(
title=config.gradio.title,
theme=config.gradio.theme
) as demo:
gr.Markdown(f"""
# {config.gradio.title}
## πŸ› οΈ Available MCP Tools
This server exposes Linux administration tools via the MCP (Model Context Protocol):
### 🟒 Safe Operations (Direct Execution)
- **run_safe_command**: Execute whitelisted read-only commands
- Whitelist: `{', '.join(config.security.safe_commands[:10])}...`
### πŸ”΄ Sensitive Operations (Require Validation)
- **add_user**: Create new system users
- **create_file**: Create files with specified content and permissions
- **change_permission**: Modify file/directory permissions
## πŸ”Œ MCP Connection
Connect MCP clients to this server to access these tools programmatically.
Each tool includes proper validation and security checks.
## πŸ“Š Tool Status
- Total Tools: {len(tools)}
- Safe Commands: {len(config.security.safe_commands)}
- Command Timeout: {config.security.command_timeout}s
""")
# Tool testing interface (optional)
with gr.Tab("Test Tools"):
gr.Markdown("### Test MCP Tools Directly")
with gr.Row():
with gr.Column():
tool_selector = gr.Dropdown(
choices=["run_safe_command", "add_user", "create_file", "change_permission"],
label="Select Tool",
value="run_safe_command"
)
# Safe command inputs
with gr.Group(visible=True) as safe_inputs:
safe_command = gr.Dropdown(
choices=config.security.safe_commands,
label="Command",
value="ls"
)
safe_args = gr.Textbox(
label="Arguments (space-separated)",
placeholder="-la /home"
)
# User inputs
with gr.Group(visible=False) as user_inputs:
username = gr.Textbox(label="Username", placeholder="john")
groups = gr.Textbox(label="Groups (comma-separated)", placeholder="sudo,users")
create_home = gr.Checkbox(label="Create Home Directory", value=True)
# File inputs
with gr.Group(visible=False) as file_inputs:
filepath = gr.Textbox(label="File Path", placeholder="/tmp/test.txt")
content = gr.Textbox(label="File Content", lines=3, placeholder="Hello, World!")
permissions = gr.Textbox(label="Permissions", value="644", placeholder="644")
test_button = gr.Button("Test Tool", variant="primary")
with gr.Column():
test_output = gr.JSON(label="Tool Output")
# Tool selector event handler
def update_inputs(tool_name):
return {
safe_inputs: gr.update(visible=(tool_name == "run_safe_command")),
user_inputs: gr.update(visible=(tool_name == "add_user")),
file_inputs: gr.update(visible=(tool_name in ["create_file", "change_permission"]))
}
tool_selector.change(
update_inputs,
inputs=[tool_selector],
outputs=[safe_inputs, user_inputs, file_inputs]
)
# Test tool execution
def test_tool(tool_name, cmd, args, user, grps, home, path, cont, perms):
try:
if tool_name == "run_safe_command":
args_list = args.split() if args else []
return run_safe_command(cmd, args_list)
elif tool_name == "add_user":
groups_list = [g.strip() for g in grps.split(",")] if grps else []
return add_user(user, groups_list, home)
elif tool_name == "create_file":
return create_file(path, cont, perms)
elif tool_name == "change_permission":
return change_permission(path, perms)
else:
return {"error": f"Unknown tool: {tool_name}"}
except Exception as e:
return {"error": str(e)}
test_button.click(
test_tool,
inputs=[
tool_selector, safe_command, safe_args,
username, groups, create_home,
filepath, content, permissions
],
outputs=[test_output]
)
# System info tab
with gr.Tab("System Info"):
gr.Markdown(f"""
### Server Configuration
- **MCP Tools**: {len(tools)} available
- **Safe Commands**: {len(config.security.safe_commands)} whitelisted
- **Command Timeout**: {config.security.command_timeout} seconds
- **OpenAI Model**: {config.openai.model}
### Security Settings
**Safe Commands Whitelist:**
```
{', '.join(config.security.safe_commands)}
```
**Sensitive Operations:**
- User management (add_user)
- File operations (create_file, change_permission)
- All require proper validation and logging
""")
# Configure MCP server
demo.mcp_tools = tools # Gradio automatically exposes these as MCP tools
return demo
def main():
"""Main entry point for the Linux MCP server"""
logger.info("Starting Linux MCP Server with Gradio")
logger.info(f"OpenAI API configured: {'βœ…' if config.openai.api_key else '❌'}")
logger.info(f"Safe commands: {len(config.security.safe_commands)}")
# Create and launch the server
demo = create_linux_mcp_server()
# Launch with MCP server enabled
demo.launch(
share=config.gradio.share,
server_name="0.0.0.0", # For HF Spaces
server_port=7860, # Standard HF Spaces port
show_error=True
)
if __name__ == "__main__":
main()