hermes-mcp

poetryprotocol/hermes-mcp

3.2

If you are the rightful owner of hermes-mcp 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.

Hermes MCP is a lightweight, reliable Model Context Protocol server designed for Claude Desktop, offering essential development tools with a focus on Windows compatibility.

Tools
14
Resources
0
Prompts
0

Hermes MCP

A lightweight, reliable MCP server for Claude Desktop with 15 essential development tools.

Platform: Windows (uses PowerShell, Git for Windows paths)
Key feature: Fixes the critical async subprocess stdin inheritance bug that causes tools to hang.

Why Hermes?

Most MCP file/shell servers are flaky. Hermes is:

  • Reliable - Proper async subprocess handling with stdin isolation
  • Complete - 15 tools covering files, shell, git, HTTP, and system utilities
  • Simple - Pure Python, ~700 lines, easy to understand and modify
  • Fast - Direct execution, no unnecessary overhead

Platform Support

Currently Windows-optimized:

  • Uses powershell.exe for shell commands
  • Git paths default to C:\Program Files\Git\
  • Path separators are Windows-style

Unix/Mac adaptation needed:

  • Replace run_powershell with run_bash
  • Update git executable detection
  • Adjust path handling

PRs for Unix/Mac support welcome!

The Critical Fix

If you're building MCP tools that spawn subprocesses, you'll hit this: subprocesses inherit MCP's stdin pipe and hang waiting for input.

The fix:

process = await asyncio.create_subprocess_exec(
    executable, *args,
    stdin=asyncio.subprocess.DEVNULL,  # THIS IS THE KEY
    stdout=asyncio.subprocess.PIPE,
    stderr=asyncio.subprocess.PIPE,
)

Without stdin=asyncio.subprocess.DEVNULL, git and shell commands will hang indefinitely in Claude Desktop.

Tools (15)

File Operations (10)

ToolDescription
read_fileRead text file contents
write_fileCreate/overwrite file
append_to_fileAppend to file
delete_fileDelete a file
copy_fileCopy file
move_fileMove/rename file
file_existsCheck existence
get_file_infoSize, dates, type
list_directoryList contents
search_filesFind by glob pattern

Shell & Git (2)

ToolDescription
run_powershellExecute PowerShell commands (Windows)
run_gitExecute Git commands

Web & API (2)

ToolDescription
fetch_urlFetch webpage as text
http_requestFull HTTP API calls

System (1)

ToolDescription
get_timeGet current local date and time

Installation

Prerequisites

  • Windows 10/11
  • Python 3.10+
  • Git for Windows
  • Claude Desktop

1. Clone the repo

git clone https://github.com/YOUR_USERNAME/hermes-mcp.git
cd hermes-mcp

2. Create virtual environment

python -m venv .venv
.venv\Scripts\activate

3. Install dependencies

pip install -r requirements.txt

4. Configure allowed paths

Edit server.py and update the ALLOWED_PATHS list to match your system:

ALLOWED_PATHS = [
    Path("C:/Users/YOUR_USERNAME/Documents"),
    Path("C:/Users/YOUR_USERNAME/Projects"),
    # Add your paths here
]

5. Add to Claude Desktop config

Edit %APPDATA%\Claude\claude_desktop_config.json:

{
  "mcpServers": {
    "hermes": {
      "command": "C:\\path\\to\\hermes-mcp\\.venv\\Scripts\\python.exe",
      "args": ["C:\\path\\to\\hermes-mcp\\server.py"]
    }
  }
}

6. Restart Claude Desktop

Usage Examples

# Read a file
hermes:read_file path="C:\Users\me\project\README.md"

# Git operations
hermes:run_git args="status" working_directory="C:\Users\me\project"
hermes:run_git args="log --oneline -5" working_directory="C:\Users\me\project"

# Search for files
hermes:search_files path="C:\Users\me\project" pattern="*.py"

# Fetch a webpage
hermes:fetch_url url="https://example.com"

# API call
hermes:http_request method="GET" url="https://api.github.com/zen"

# POST with JSON
hermes:http_request method="POST" url="https://api.example.com/data" json_body={"key": "value"}

# Get current time
hermes:get_time

Security

  • File operations are restricted to paths in ALLOWED_PATHS
  • Web/API tools have no URL restrictions (intentional for development)
  • No authentication or rate limiting (local use only)

Dependencies

  • mcp - Model Context Protocol SDK
  • httpx - Async HTTP client

Technical Details

Async Subprocess Pattern

async def run_command(...):
    process = await asyncio.create_subprocess_exec(
        executable, *args,
        stdin=asyncio.subprocess.DEVNULL,  # Prevents stdin inheritance
        stdout=asyncio.subprocess.PIPE,
        stderr=asyncio.subprocess.PIPE,
        cwd=working_dir
    )
    
    try:
        stdout, stderr = await asyncio.wait_for(
            process.communicate(),
            timeout=30
        )
    except asyncio.TimeoutError:
        process.kill()
        await process.wait()
        # Handle timeout

Why stdin=DEVNULL?

MCP servers communicate via stdio. When you spawn a subprocess, it inherits the parent's stdin by default. This means:

  1. Your subprocess's stdin points to MCP's communication pipe
  2. If the subprocess tries to read stdin (git, shell, etc.), it blocks
  3. The MCP message it reads isn't valid input, causing hangs or errors

Setting stdin=DEVNULL tells the subprocess "you have no stdin" - it won't try to read, and won't interfere with MCP's communication.

Troubleshooting

Tools hang indefinitely

  • Check that stdin=asyncio.subprocess.DEVNULL is set
  • Verify the executable path exists

"Path not allowed" errors

  • Add your paths to ALLOWED_PATHS in server.py

Git not found

  • Install Git for Windows
  • Check the paths in run_git match your installation

Contributing

PRs welcome. Key areas:

  • Unix/Mac support - Replace PowerShell with bash, update paths
  • Additional tools
  • Better error messages

License

MIT

Credits

The stdin fix was discovered through painful debugging - hopefully it saves you time.


Named after Hermes, messenger of the gods - because that's what MCP servers do.