devout

erlsci/devout

3.3

If you are the rightful owner of devout and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to dayong@mcphub.com.

Devout is a secure file management service using the Model Context Protocol (MCP) for integration with Claude Desktop, built with Erlang/OTP.

Tools
7
Resources
0
Prompts
0

Devout

A Devin Clone MCP Server

A Model Context Protocol (MCP) server written in Erlang that provides file, directory, and version control operations for software projects.

Features

🛠️ File Operations

  • new-dir: Create directories with automatic parent creation
  • new-dirs: Create directory structures with multiple children
  • move: Safely move/rename files and directories
  • write: Create/write files with append mode support
  • read: Read file contents with size limits
  • list-files: List directory contents with file types and sizes
  • show-cwd: Display current working directory
  • change-cwd: Navigate to relative directories

🐙 Git Operations

  • git-add: Add files to staging area (git add <files>)
  • git-log: Show commit history (git log [options])
  • git-diff: Show differences (no args, 1 arg, or 2 args)
  • git-pull: Pull with rebase (git pull <remote> <branch> --rebase)
  • git-checkout-branch: Create and checkout new branch (git checkout -b <name>)
  • git-push: Push to remote (git push <remote>)
  • git-commit-all: Commit all changes (git commit -a -m <message>)
  • git-commit-files: Commit specific files (git commit <files> -m <message>)
  • git-clone: Clone repository (git clone <url>)
  • git-status: Show repository status (git status --porcelain)

🔒 Security Features

  • Path Validation: Only relative paths allowed, prevents directory traversal
  • Sandboxing: All operations restricted to base directory
  • File Size Limits: Configurable maximum file sizes
  • Extension Filtering: Optional file type restrictions
  • Safe Error Handling: No information disclosure through errors

📚 Resources & Prompts

  • devout://status: Real-time service status and configuration
  • devout://help: Comprehensive tool documentation
  • create_project: Intelligent project structure generation (Erlang, web, API, library)

Architecture

OTP Design

  • Application: devout_app - Standard OTP application callback
  • Supervisor: devout_sup - Manages server process lifecycle
  • Server: devout_server - Main gen_server coordinating with erlmcp
  • Operations: devout_fs - File system operation implementations
  • Validation: devout_path_validator - Security and path validation
  • Git Operations: devout_git - Git command implementations
  • Entry Point: devout_stdio_main - Standalone stdio executable

Security Model

┌─────────────────┐    ┌──────────────────┐    ┌─────────────────┐
│   Claude AI     │───▶│   devout_server  │───▶│    devout_fs    │
└─────────────────┘    └──────────────────┘    └─────────────────┘
                            │      │                    │
                            │      ▼                    ▼
                       ┌──────────────────┐    ┌─────────────────┐
                       │ erlmcp_stdio     │    │ path_validator  │
                       │ (MCP Protocol)   │    │ (Security)      │
                       └──────────────────┘    └─────────────────┘
                            │
                            ▼
                       ┌──────────────────┐    ┌─────────────────┐
                       │    devout_git    │───▶│     erlexec     │
                       └──────────────────┘    │ (Proc. Mgmt.)   │
                                               └─────────────────┘

Prerequisites

  • Erlang/OTP 25+
  • Rebar3
  • Git (for dependencies & Git operations)

Quick Start

1. Build

git clone <repository-url>
cd devout
rebar3 get-deps
rebar3 compile

2. Test

rebar3 eunit

3. Configure Claude Desktop

Edit claude_desktop_config.json:

macOS: ~/Library/Application Support/Claude/claude_desktop_config.json Windows: %APPDATA%\Claude\claude_desktop_config.json Linux: ~/.config/Claude/claude_desktop_config.json

{
  "mcpServers": {
    "devout": {
        "command": "/Users/oubiwann/lab/erlsci/devout/bin/start.sh",
        "args": []
    }
  }
}

4. Restart Claude Desktop

Usage Examples

📁 Directory Operations

User: Create a new project structure called "my_app" with src, test, and docs directories

Claude: I'll create that project structure for you.

[Uses new-dirs tool: {"path": "my_app", "children": ["src", "test", "docs"]}]

Directory structure created successfully:
  - my_app
  - src
  - test
  - docs

🔍 Directory Exploration

User: What files are in the current directory?

Claude: I'll show you the files in the current directory.

[Uses list-files tool: {}]

Contents of .:
[FILE] .DS_Store (6148 bytes)
[DIR] .git
[DIR] .github
[FILE] .gitignore (164 bytes)
[FILE] LICENSE (11358 bytes)
[FILE] Makefile (4612 bytes)
[FILE] README.md (9895 bytes)
[DIR] _build
[DIR] bin
[DIR] config
[DIR] src
[DIR] test

📝 File Operations

User: Create a configuration file with some JSON content

Claude: I'll create a config file for you.

[Uses write tool: {"path": "my_app/config.json", "content": "{\n  \"port\": 3000,\n  \"debug\": true\n}"}]

Content written to file successfully: my_app/config.json (32 bytes)
🔍 Navigation & Reading
User: Show me the current directory and then read the config file

Claude: I'll show the current directory and read the config file.

[Uses show-cwd tool: {}]
Current working directory: /Users/developer/projects

[Uses read tool: {"path": "my_app/config.json"}]
Content of my_app/config.json (32 bytes):

{
  "port": 3000,
  "debug": true
}
🏗️ Project Generation
User: Use the create_project prompt for an Erlang application

Claude: I'll generate an Erlang project structure prompt.

[Uses create_project prompt: {"project_name": "my_erlang_app", "project_type": "erlang"}]

Create a project structure for 'my_erlang_app' (erlang project). Create an Erlang/OTP project structure with directories: src, include, test, priv, rebar.config. Use the devout tools to create the necessary directories and files.

🐙 Git Operations

View Git History
User: Show me the last 5 commits

Claude: I'll show you the recent commit history.

[Uses git-log tool: {"args": "--oneline -5"}]

Git log:
a1b2c3d Add new feature
e4f5g6h Fix bug in parser
i7j8k9l Update documentation
m1n2o3p Initial commit
Create Feature Branch
User: Create a new feature branch called "user-authentication"

Claude: I'll create and checkout a new branch for you.

[Uses git-checkout-branch tool: {"branch": "user-authentication"}]

Git checkout branch successful:
Switched to a new branch 'user-authentication'
Commit Changes
User: Add these files to git and commit them with message "Add user auth"

Claude: I'll stage and commit those files for you.

[Uses git-add tool: {"files": ["src/auth.erl", "test/auth_test.erl"]}]
[Uses git-commit-files tool: {"files": ["src/auth.erl", "test/auth_test.erl"], "message": "Add user auth"}]

Git operations successful!
Sync with Remote
User: Pull latest changes from origin main and then push my branch

Claude: I'll sync with the remote repository for you.

[Uses git-pull tool: {"remote": "origin", "branch": "main"}]
[Uses git-push tool: {"remote": "origin"}]

Git sync completed successfully!

Configuration

Edit config/sys.config to customize behavior:

[
    {devout, [
        {max_file_size, 10485760},          % 10MB limit
        {allowed_extensions, all},          % or [<<".txt">>, <<".md">>]
        {enable_recursive_delete, false},   % Safety first
        {allowed_operations, [              % Restrict available operations
            new_dir, new_dirs, move, write, read, list_files, show_cwd, change_cwd
        ]}
    ]},

    {erlexec, [
        {debug, false},                     % Enable for git command debugging
        {verbose, false}
    ]}
].

Git Command Reference

MCP ToolGit CommandDescription
git-addgit add <files>Stage files for commit
git-loggit log [options]Show commit history
git-diffgit diff [ref1] [ref2]Show differences
git-pullgit pull <remote> <branch> --rebasePull with rebase
git-checkout-branchgit checkout -b <name>Create new branch
git-pushgit push <remote>Push to remote
git-commit-allgit commit -a -m <message>Commit all changes
git-commit-filesgit commit <files> -m <message>Commit specific files
git-clonegit clone <url>Clone repository
git-statusgit status --porcelainShow repo status

Git Tool Parameters

git-add
{
  "files": ["file1.txt", "file2.txt"]  // Array of files
  // OR
  "file": "single_file.txt"            // Single file
}
git-log
{
  "args": "--oneline -10"              // Optional: git log arguments
}
git-diff
{
  // No parameters = working directory vs staged
  // OR
  "ref": "HEAD~1"                      // Compare against reference
  // OR
  "ref1": "HEAD~2",                    // Compare two references
  "ref2": "HEAD~1"
}
git-pull
{
  "remote": "origin",                  // Required: remote name
  "branch": "main"                     // Required: branch name
}
git-push
{
  "remote": "origin"                   // Required: remote name
}

Security Features

🛡️ Path Security

  • Relative Paths Only: Absolute paths rejected (/etc/passwd ❌)
  • Traversal Prevention: Parent directory access blocked (../../../etc ❌)
  • Base Directory Enforcement: Operations confined to working directory
  • Path Normalization: Handles ./, //, and other edge cases

📏 Resource Limits

  • File Size Limits: Configurable maximum file sizes (default: 10MB)
  • Operation Whitelisting: Restrict available operations per deployment
  • Extension Filtering: Optional file type restrictions
  • Memory Protection: Streaming for large files

🔒 Error Handling

  • Information Hiding: Errors don't leak system details
  • Graceful Degradation: Partial failures handled cleanly
  • Audit Logging: All operations logged for security review
  • Input Sanitization: All inputs validated before processing

Development

Running Tests

# Full test suite
rebar3 eunit

# Specific test modules
rebar3 eunit --module=devout_test

# With coverage
rebar3 cover

Code Quality

# Static analysis
rebar3 dialyzer

# Cross references
rebar3 xref

# Linting
rebar3 lint

Development Mode

# Interactive shell
rebar3 shell

# Start stdio server manually
devout_server:start_stdio().

Adding FS Operations

  1. Add to allowed_operations in devout.app.src

  2. Implement in devout_fs.erl (if needed):

    my_operation(Path) ->
        case devout_path_validator:validate_path(Path) of
            {ok, ValidPath} ->
                % Your operation here
                ok;
            {error, Reason} ->
                {error, Reason}
        end.
    
  3. Register tool in devout_app.erl:

    ok = erlmcp_stdio:add_tool(
        <<"my-operation">>,
        <<"Description">>,
        fun devout_server:handle_my_operation/1,
        SchemaMap
    ).
    
  4. Add handler in devout_server.erl:

    handle_my_operation(#{<<"path">> := Path}) ->
        case devout_fs:my_operation(Path) of
            ok -> <<"Success message">>;
            {error, Reason} -> devout_fmt:err(Reason)
        end.
    

Adding New Git Operations

  1. Add function to devout_git.erl:

    my_git_operation(Args) ->
        execute_git(["my-operation"] ++ Args).
    
  2. Add MCP handler:

    handle_my_git_operation(#{<<"param">> := Value}) ->
        case my_git_operation([binary_to_list(Value)]) of
            {ok, Output} -> <<"Success: ", Output/binary>>;
            {error, Reason} -> devout_fmt:err(Reason)
        end.
    
  3. Register tool in devout_server.erl:

    ok = erlmcp_stdio:add_tool(
        <<"git-my-operation">>,
        <<"Description of my git operation">>,
        fun devout_git:handle_my_git_operation/1,
        Schema
    ).
    
  4. Add tests in devout_git_test.erl

Monitoring & Debugging

Health Checks

# Check if application is running
erl -eval "io:format('~p~n', [application:which_applications()]), halt()."

# Verify processes
erl -eval "io:format('~p~n', [whereis(devout_server)]), halt()."

Logging

Logs go to stderr to avoid interfering with MCP protocol on stdout:

  • Info: Service lifecycle events
  • Warning: Security violations, invalid paths
  • Error: Operation failures, system errors

Troubleshooting

IssueCauseSolution
Service not startingMissing dependenciesrebar3 get-deps && rebar3 compile
Path rejectedAbsolute/traversal pathUse relative paths only
File too largeExceeds size limitCheck max_file_size config
Permission deniedFile system permissionsCheck directory ownership
Tool not foundVersion mismatchVerify erlmcp compatibility
Git command timeoutLong-running operationIncrease timeout in erlexec config
Git not foundMissing git installationInstall git and ensure it's in PATH
Merge conflictsConflicting changesResolve conflicts manually
Repository not foundNot in git repositoryInitialize with git init first

Performance

  • Memory Usage: ~10MB base + file buffers
  • Throughput: 1000+ operations/second for small files
  • Latency: <10ms for typical operations
  • Scalability: Single-threaded, suitable for interactive use

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Add tests for new functionality
  4. Ensure all tests pass: rebar3 eunit
  5. Run static analysis: rebar3 dialyzer
  6. Submit a pull request

Code Style

  • Use OTP principles and gen_server patterns
  • Comprehensive error handling with proper types
  • Security-first design - validate all inputs
  • Document all public functions with edoc
  • Follow Erlang naming conventions

Acknowledgments

  • Built on the excellent erlmcp library
  • Inspired by security practices from the Erlang/OTP ecosystem
  • Thanks to the Claude Desktop team for MCP protocol specification

License

Apache License 2.0 - see LICENSE file for details.

External Resources