Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 35 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,18 @@

ShellMCP is a powerful tool that allows you to easily create Model Context Protocol (MCP) servers by exposing shell commands as structured tools. Instead of granting AI agents full shell access (which poses security risks), ShellMCP enables you to expose only the specific commands you trust, allowing agents to work autonomously with a predefined set of safe operations.

Define your tools in YAML, and ShellMCP generates a complete FastMCP server for you.
Define your tools in YAML, and ShellMCP generates and runs a complete FastMCP server for you.

## Quick Start

```bash
# Install ShellMCP
pip install shellmcp

# Create a new server configuration
# Run a built-in MCP server directly
shellmcp run basics

# Or create a custom server configuration
shellmcp new --name "my-server" --desc "My custom MCP server"

# Add a tool interactively
Expand All @@ -23,18 +26,22 @@ shellmcp validate my-server.yml

# Generate the FastMCP server
shellmcp generate my-server.yml

# Or run directly from a YAML file
shellmcp run --config_file my-server.yml
```

## Features

- 🚀 **Simple YAML Configuration**: Define tools, resources, and prompts in clean YAML
- 🚀 **Simple YAML Configuration**: Define tools and resources in clean YAML
- 🔧 **Interactive CLI**: Add tools and resources with guided prompts
- 📝 **Template Support**: Use Jinja2 templates for dynamic command generation
- ✅ **Validation**: Built-in configuration validation and error checking
- 🎯 **FastMCP Integration**: Generates production-ready FastMCP servers
- 📦 **Complete Output**: Includes server code, requirements, and documentation
- 🎯 **FastMCP Integration**: Generates and runs production-ready FastMCP servers
- 📦 **Built-in Configurations**: Pre-configured servers ready to run
- 🔒 **Security-First**: Expose only trusted commands to AI agents
- 🎨 **Flexible**: Support for tools, resources, and prompts with reusable arguments
- 🎨 **Flexible**: Support for tools and resources with reusable arguments
- ⚡ **Instant Execution**: Run servers directly from YAML without generating files

## Example

Expand Down Expand Up @@ -103,6 +110,28 @@ prompts:

ShellMCP provides several commands to help you create and manage MCP servers:

### `shellmcp run`
Run an MCP server directly from a built-in configuration or YAML file.

```bash
# Run a built-in configuration
shellmcp run basics

# Run from a custom YAML file
shellmcp run --config_file my-server.yml
```

Built-in configurations:
- **basics**: Basic shell operations for file system, process management, and system information

The `basics` configuration includes tools for:
- File operations (list, find, copy, move, delete)
- Directory management (create, remove, navigate)
- Process management (list, kill processes)
- System information (memory, disk, network)
- Text operations (read, write, search)
- Resources for system status and environment info

### `shellmcp new`
Create a new server configuration file.

Expand Down
5 changes: 3 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "shellmcp"
version = "1.0.0"
version = "1.1.0"
description = "Expose Shell Commands as MCP tools"
readme = "README.md"
requires-python = ">=3.8"
Expand All @@ -14,6 +14,7 @@ dependencies = [
"jinja2>=3.0.0",
"fire>=0.5.0",
"questionary>=2.0.0",
"fastmcp>=0.1.0",
]

[project.optional-dependencies]
Expand All @@ -30,7 +31,7 @@ where = ["."]
include = ["shellmcp*"]

[tool.setuptools.package-data]
shellmcp = ["templates/*.j2"]
shellmcp = ["templates/*.j2", "configs/*.yml"]

[project.scripts]
shellmcp = "shellmcp.cli:main"
Expand Down
2 changes: 1 addition & 1 deletion shellmcp/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""ShellMCP - Expose Shell Commands as MCP tools."""

__version__ = "1.0.0"
__version__ = "1.1.0"
92 changes: 91 additions & 1 deletion shellmcp/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,23 @@
YMLConfig,
)
from .parser import YMLParser
from .generator import FastMCPGenerator
from .utils import get_choice, get_input, get_yes_no, load_or_create_config, save_config


def _get_builtin_config(config_name: str) -> str:
"""Get path to a built-in configuration file."""
from pathlib import Path
config_dir = Path(__file__).parent / "configs"
config_file = config_dir / f"{config_name}.yml"

if not config_file.exists():
available_configs = [f.stem for f in config_dir.glob("*.yml")]
raise ValueError(f"Built-in config '{config_name}' not found. Available configs: {', '.join(available_configs)}")

return str(config_file)


def _handle_error(error_msg: str, verbose: bool = False, exception: Exception = None) -> int:
"""Common error handling for CLI functions."""
print(f"❌ {error_msg}", file=sys.stderr)
Expand Down Expand Up @@ -538,6 +552,81 @@ def add_prompt(config_file: str, name: str = None, prompt_name: str = None, desc
return _handle_error(f"Error adding prompt: {e}", exception=e)


def run(config_name: str = None, config_file: str = None) -> int:
"""
Run an MCP server from a built-in configuration or YAML file.

Args:
config_name: Name of built-in configuration (e.g., 'basics')
config_file: Path to YAML configuration file

Returns:
Exit code (0 for success, 1 for failure)
"""
try:
if config_name and config_file:
return _handle_error("Cannot specify both config_name and config_file. Use one or the other.")

if not config_name and not config_file:
return _handle_error("Must specify either config_name (for built-in configs) or config_file (for custom configs)")

# Determine which config to use
if config_name:
# Use built-in configuration
try:
config_path = _get_builtin_config(config_name)
print(f"🚀 Starting built-in MCP server: {config_name}")
print(f"📁 Configuration: {config_path}")
except ValueError as e:
return _handle_error(str(e))
else:
# Use custom configuration file
if not _check_file_exists(config_file):
return _handle_error(f"Configuration file '{config_file}' not found")

config_path = config_file
print(f"🚀 Starting MCP server from configuration: {config_file}")

# Generate and run the server
_generate_and_run_server(config_path)
return 0

except Exception as e:
return _handle_error(f"Error running MCP server: {e}", exception=e)


def _generate_and_run_server(config_file: str):
"""Generate MCP server code and execute it."""
import tempfile
import subprocess
import os
from pathlib import Path

# Load and validate configuration
parser = YMLParser()
config = parser.load_from_file(config_file)

# Generate server code
generator = FastMCPGenerator()
server_code = generator._generate_server_code(config)

# Create a temporary file for the server
with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:
f.write(server_code)
temp_server_file = f.name

try:
# Execute the generated server
print(f"🐍 Executing generated MCP server...")
subprocess.run([sys.executable, temp_server_file], check=True)
finally:
# Clean up temporary file
try:
os.unlink(temp_server_file)
except OSError:
pass # File might already be deleted


def main():
"""Main CLI entry point using Fire."""
fire.Fire({
Expand All @@ -546,5 +635,6 @@ def main():
'new': new,
'add-tool': add_tool,
'add-resource': add_resource,
'add-prompt': add_prompt
'add-prompt': add_prompt,
'run': run
})
1 change: 1 addition & 0 deletions shellmcp/configs/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Pre-configured MCP server configurations."""
Loading