# Local MCP File Editing

> Use local-mcp to enable AI agents to safely read, write, and execute commands on local files with sandboxed permissions

- Skill: `aradotso/local-mcp-file-editing` (Agent Skill)
- Install (CLI): `npx skillmds@latest add aradotso/local-mcp-file-editing`
- Raw SKILL.md: https://api.skillmd.com/api/skills/aradotso/local-mcp-file-editing/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: aradotso (https://skillmd.com/u/aradotso)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/aradotso/local-mcp-file-editing

---


# local-mcp File Editing Skill

> Skill by [ara.so](https://ara.so) — MCP Skills collection.

## Overview

`local-mcp` is a Rust-based MCP (Model Context Protocol) server that exposes local filesystem and command execution capabilities to AI agents. It provides:

- **File operations**: Read, write, and list files
- **Image reading**: Native MCP image content for PNG, JPEG, GIF, WebP, BMP, TIFF, AVIF
- **Sandboxed command execution**: Network-isolated commands using Landlock (Linux) or Seatbelt (macOS)
- **Session-based permissions**: Each project gets its own permission context
- **Live activity monitoring**: Real-time diffs and command output in the start UI
- **Background job management**: Long-running commands with polling support

Commands run sandboxed by default (no network access). Unsandboxed commands require explicit approval through the interactive UI.

## Installation

### From Source (Cargo)

```sh
# Clone and build
git clone https://github.com/nakasyou/local-mcp.git
cd local-mcp
cargo build --release

# Binary will be at target/release/local-mcp
# On Linux, also outputs target/release/codex-linux-sandbox
```

### With Nix

```sh
# Run directly
nix run github:nakasyou/local-mcp

# Or build locally
nix build
./result/bin/local-mcp

# Development shell
nix develop
```

### System Requirements

- **Linux**: Requires `bwrap` (bubblewrap) in PATH, plus the `codex-linux-sandbox` helper binary
- **macOS**: Uses system `/usr/bin/sandbox-exec`, no extra dependencies
- **Windows**: Not yet supported

## Starting the Server

### 1. Start the MCP Server

```sh
# Run the persistent MCP server
local-mcp mcp

# Server listens on Unix domain sockets for each session
```

### 2. Start a Session

```sh
# Start session in your project directory
cd /path/to/your/project
local-mcp start

# Or use a stable session ID
local-mcp start my-project-name

# Session ID is printed - give this to your AI agent
```

The session working directory is where you ran `local-mcp start`. All relative paths resolve from there.

## Permission Management

In the `local-mcp start` UI, manage permissions with these commands:

```sh
# Allow all unsandboxed commands (for session lifetime only)
/permissions yolo

# Require approval for each unsandboxed command
/permissions ask

# Allow access to specific directory outside working dir
/permissions allow ../another-project

# Revoke directory permission
/permissions revoke ../another-project

# List all permissions
/permissions list

# Show current permission status
/permissions status
```

**Note**: `/permission` (singular) is also accepted.

## MCP Tools API

All tools require a `session_id` parameter (provided by the agent).

### session_info

Confirm session configuration and working directory.

```rust
// Tool parameters
{
    "session_id": "my-project-name"
}

// Returns
{
    "working_directory": "/path/to/your/project",
    "sandbox_roots": ["/path/to/your/project"],
    "permission_mode": "yolo" // or "ask"
}
```

### read_file

Read text file contents.

```rust
{
    "session_id": "my-project-name",
    "path": "src/main.rs"  // Relative to working directory
}

// Returns file content as string
```

### get_image

Read image files as native MCP image content. Supports PNG, JPEG, GIF, WebP, BMP, TIFF, AVIF.

```rust
{
    "session_id": "my-project-name",
    "path": "assets/logo.png"
}

// Returns MCP image content
```

### list_directory

List directory contents with file metadata.

```rust
{
    "session_id": "my-project-name",
    "path": "src"  // Optional, defaults to working directory
}

// Returns array of file entries with size, modified time, type
```

### write_file

Write or modify a file (sandboxed within working directory).

```rust
{
    "session_id": "my-project-name",
    "path": "config.toml",
    "content": "[server]\nport = 8080\n"
}

// Shows unified diff in start UI
```

### execute

Run a command, sandboxed (no network access). Returns immediately for commands under 30 seconds, otherwise returns a job_id.

```rust
{
    "session_id": "my-project-name",
    "command": "cargo build",
    "args": ["--release"],
    "cwd": "."  // Optional, relative to working dir
}

// Quick commands return:
{
    "stdout": "   Compiling local-mcp v0.1.0\n...",
    "stderr": "",
    "exit_code": 0
}

// Long commands return:
{
    "job_id": "abc123",
    "message": "Command started in background"
}
```

### without_sandbox

Execute command with full network and host permissions. **Requires approval** unless `/permissions yolo` is set.

```rust
{
    "session_id": "my-project-name",
    "command": "curl",
    "args": ["https://api.example.com/data"],
    "cwd": "."
}

// Same return format as execute
```

### start_command

Start a background command immediately (sandboxed). Always returns a job_id without waiting.

```rust
{
    "session_id": "my-project-name",
    "command": "cargo",
    "args": ["watch", "-x", "test"]
}

// Returns:
{
    "job_id": "def456"
}
```

### poll_job

Check status of a background job.

```rust
{
    "session_id": "my-project-name",
    "job_id": "abc123"
}

// Still running:
{
    "status": "running"
}

// Completed:
{
    "status": "completed",
    "stdout": "...",
    "stderr": "...",
    "exit_code": 0
}
```

### stop_job

Terminate a background job.

```rust
{
    "session_id": "my-project-name",
    "job_id": "abc123"
}

// Returns confirmation
```

## Common Patterns

### Multi-File Refactoring

```rust
// 1. List files to refactor
list_directory({ session_id: "proj", path: "src" })

// 2. Read each file
read_file({ session_id: "proj", path: "src/main.rs" })
read_file({ session_id: "proj", path: "src/lib.rs" })

// 3. Write updated content
write_file({
    session_id: "proj",
    path: "src/main.rs",
    content: "// Updated code..."
})

// 4. Run tests (sandboxed)
execute({
    session_id: "proj",
    command: "cargo",
    args: ["test"]
})
```

### Building and Deploying

```rust
// 1. Build (sandboxed, no network)
execute({
    session_id: "proj",
    command: "cargo",
    args: ["build", "--release"]
})

// 2. Deploy (requires network, needs approval)
without_sandbox({
    session_id: "proj",
    command: "scp",
    args: ["target/release/app", "user@server:/opt/"]
})
```

### Long-Running Dev Server

```rust
// Start dev server in background
start_command({
    session_id: "proj",
    command: "cargo",
    args: ["run", "--", "serve"]
})
// Returns: { job_id: "server-xyz" }

// Check if server started
poll_job({
    session_id: "proj",
    job_id: "server-xyz"
})

// Later, stop it
stop_job({
    session_id: "proj",
    job_id: "server-xyz"
})
```

### Working with Images

```rust
// List images
list_directory({ session_id: "proj", path: "assets/images" })

// Load image for analysis
get_image({
    session_id: "proj",
    path: "assets/screenshot.png"
})
// Returns native MCP image content for vision analysis
```

## Configuration

### Session Configuration

Sessions are configured through the `local-mcp start` command and the interactive UI. Configuration is **session-lifetime only** and includes:

- Working directory (set by where `start` was run)
- Permission mode (`ask` or `yolo`)
- Approved directories outside working dir

### Environment Variables

The project uses standard Rust environment variables during build:

- `CARGO_BUILD_TARGET`: Target triple for cross-compilation
- `RUSTFLAGS`: Compiler flags

No runtime environment variables are required.

### MCP Server Configuration

The server runs on Unix domain sockets (one per session). Socket paths are managed internally and communicated to the `start` UI automatically.

## Troubleshooting

### "bwrap not found" (Linux)

Install bubblewrap:

```sh
# Debian/Ubuntu
sudo apt install bubblewrap

# Fedora
sudo dnf install bubblewrap

# Arch
sudo pacman -S bubblewrap
```

### "codex-linux-sandbox not found" (Linux)

The helper binary must be in the same directory as `local-mcp`:

```sh
# After building
ls target/release/
# Should show: local-mcp  codex-linux-sandbox

# When installing, copy both
sudo cp target/release/local-mcp /usr/local/bin/
sudo cp target/release/codex-linux-sandbox /usr/local/bin/
```

### Commands Failing with Permission Denied

Check your permission mode in the start UI:

```sh
/permissions status

# If in "ask" mode and you want to auto-approve:
/permissions yolo
```

For paths outside the working directory, explicitly allow them:

```sh
/permissions allow /path/to/other/directory
```

### Session ID Not Working

Ensure the session ID only contains:
- Letters (a-z, A-Z)
- Numbers (0-9)
- Hyphens (`-`)
- Underscores (`_`)
- Periods (`.`)

Invalid characters will be rejected.

### Background Jobs Not Returning Output

Use `poll_job` to check status:

```rust
poll_job({ session_id: "proj", job_id: "job-id" })
```

Jobs may still be running. Check the `status` field in the response.

### macOS Sandbox Restrictions

macOS `sandbox-exec` profiles are more restrictive. If sandboxed commands fail unexpectedly, try `without_sandbox` (requires approval).

## Security Considerations

- **Sandboxed commands** have no network access and can't escape the working directory tree
- **Unsandboxed commands** run with full host permissions and require explicit approval (unless `yolo` mode)
- **YOLO mode** only lasts for the session lifetime; restart `local-mcp start` to reset to `ask` mode
- **Session sockets** are permission-restricted Unix domain sockets
- Give session IDs only to trusted agents; anyone with the ID can make tool calls

## Integration Example

When integrating with an AI agent:

1. Start the MCP server: `local-mcp mcp`
2. Start your project session: `cd /your/project && local-mcp start my-proj`
3. In your agent prompt, include:

```
I'm working in a local-mcp session with ID "my-proj". 
Use session_info to confirm the working directory, then use 
the MCP tools to read, edit, and test files.
```

4. Set permissions as needed in the UI
5. The agent can now safely interact with your local filesystem

