Skip to main content
Glama
ckanthony

Chisel

by ckanthony

Chisel

CI codecov MCP server with tools

🪛 Rust powered precision file operations for agents. Unix-native tools, minimal context footprint, strict path confinement: use directly with Chisel MCP or bring your own MCP, embeddable in any MCP server in Rust, Python, Nodejs.

https://github.com/user-attachments/assets/af84f1af-db47-4e42-808b-00861504cd34

Install — download a pre-built .mcpb bundle (one-click, no build step) or a raw binary from the Releases page — see Standalone usage below.


Agent skill includedskills/chisel/SKILL.md teaches agents how to use Chisel at maximum efficiency. Install with: npx skills add ckanthony/Chisel

Security hardened — Verified properties across two layers: the MCP server (chisel) and the portable core library (chisel-core). See the Security model section for the full breakdown.


Contents


Related MCP server: Readedit

Motivation

Most MCP file tools hand an LLM a blank canvas: read anything, write anything, make any mistake. Chisel takes the opposite approach:

  • Reduce context overhead — every tool call is compact. File edits go through patch_apply: the model sends only a unified diff instead of rewriting an entire file, so large-file edits cost a fraction of the tokens

  • Familiar command patternsshell_exec exposes the same Unix tools (grep, sed, awk, find, cat, …) LLMs already know well from training data, so prompts stay short and outputs are predictable

  • Precision over flexibility — a fixed whitelist and strict path confinement mean the model cannot accidentally escape scope or run arbitrary commands

  • Safety first — bearer-token auth, 127.0.0.1-only binding, symlink-aware root confinement, atomic writes, and a read-only mode are all on by default

  • Reusable corechisel-core is a plain synchronous Rust library; any MCP server (Rust, Node.js via WASM, Python via WASM) can embed it without running a second process

Real-world demo

Six tasks on the same markdown file. Left: typical MCP file server. Right: chisel.

File: docs/api.md — 300 lines, 6 headers, one section of ~20 lines.


Task 1 — find all headers

# Typical                                    # Chisel
tool: read_file                              tool: shell_exec
  path: /data/docs/api.md                     command: grep
                                               args: ["-n", "^#", "/data/docs/api.md"]
← 300 lines returned (~3 000 tokens)         ← 6 lines returned (~30 tokens)
  model must scan the whole file               1:# API Reference
                                              45:## Authentication
                                              89:## Endpoints
                                             134:## Request Format
                                             178:## Response Format
                                             234:## Errors

Task 2 — read the content under ## Endpoints

# Typical                                    # Chisel
tool: read_file  (again, or re-use above)    tool: shell_exec
  path: /data/docs/api.md                     command: sed
                                               args: ["-n", "/^## Endpoints/,/^## /p",
← 300 lines returned again (~3 000 tokens)          "/data/docs/api.md"]
  model must locate the section in context
                                             ← 44 lines returned (~440 tokens)
                                               only the Endpoints section

Task 3 — edit one line in that section

# Typical                                    # Chisel
tool: write_file                             tool: patch_apply
  path: /data/docs/api.md                     path: /data/docs/api.md
  content: <entire 300-line file              patch: |
            with one line changed>              --- a/docs/api.md
                                               +++ b/docs/api.md
← 300 lines uploaded (~3 000 tokens)           @@ -91,1 +91,1 @@
  any hallucination corrupts the file          -GET /v1/items
                                               +GET /v2/items

                                             ← 7 lines uploaded (~50 tokens)
                                               hunk mismatch → PatchFailed, file untouched

Task 4 — replace all - with : in that section

# Typical                                    # Chisel
tool: read_file                              tool: shell_exec
  path: /data/docs/api.md                     command: sed
                                               args: ["-i", "s/-/:/g",
← 300 lines returned (~3 000 tokens)                "/data/docs/api.md"]
tool: write_file
  content: <300 lines with replacement>       ← 1 line call, 0 file content transmitted
← 300 lines uploaded (~3 000 tokens)           sed runs the replacement in-place

Total: ~12 000 tokens                        Total: ~520 tokens   (23× less)

Task 5 — model tries to run rm -rf ~

# Typical                                    # Chisel
  (no shell tool exposed)                    tool: shell_exec
                                               command: rm
                                               args: ["-rf", "~"]
  not applicable — typical MCP file
  servers have no shell tool, so the        ← CommandNotAllowed
  model would need a separate shell           "rm" is not in the whitelist.
  MCP or use write_file to script it          Permitted: grep sed awk find cat
                                               head tail wc sort uniq cut tr
                                               diff file stat ls du rg
                                             process is never spawned

rm, bash, sh, curl, chmod, sudo — none of these are in the whitelist. The list is fixed at compile time; it cannot be extended at runtime by the model.

Task 6 — model tries to edit /Users/home/.ssh/config directly

# Typical                                    # Chisel
tool: write_file                             tool: patch_apply
  path: /Users/home/jor/.ssh/config               path: /Users/home/jor/.ssh/config
  content: <malicious key appended>           patch: <adds authorized_keys entry>

← succeeds if the server process            ← OutsideRoot
  has filesystem access — no path             resolved path /Users/home/.ssh/config
  confinement in a naive file server          does not start with root /data
                                             I/O is never performed

Every path — including those passed to shell_exec — is validated against the configured root before any I/O or process spawn. An absolute path outside root is always rejected, regardless of which tool is called.


Context cost comparison

Estimates use Claude Sonnet 4.6 tokenisation: typical source code averages ~10 tokens/line (identifiers, punctuation, and whitespace each count as tokens under BPE).

Single edit — 500-line file, 5 lines changed:

Naive (read_filewrite_file)

Chisel (patch_apply)

Reduction

Tokens in (upload)

~5 000 (full file)

~120 (11 diff lines + headers)

42×

Tokens out (model output)

~5 000 (full file rewrite)

~15 (success ack)

333×

Round-trip total

~10 000

~135

~74×

Failure mode

Silent hallucination corrupts entire file

PatchFailed — original untouched

Read / search — 2 000-line file:

Task

Naive (read_file full)

Chisel (shell_exec)

Reduction

Find a symbol

~20 000 tokens (full read)

~40 tokens (grep matched lines)

500×

Count occurrences

~20 000 tokens

~5 tokens (grep -c integer)

4 000×

Extract lines 40–60

~20 000 tokens

~210 tokens (sed -n '40,60p')

95×

Directory tree

~20 000 tokens

~300 tokens (find / ls -R)

67×

Savings scale linearly with file size. A 2 000-line file costs 4× more than the 500-line baseline above.


Tools

Every path argument is canonicalized and confined to the configured root before any I/O — .. traversal and symlink escapes are rejected. This confinement is enforced inside chisel-core and applies equally when the library is embedded directly.

When using the MCP server (chisel), all tools additionally require Authorization: Bearer <secret>.

Tool

Description

patch_apply

Apply a unified diff atomically; accepts raw or ````diff` fenced patches — primary edit tool; sends only changed lines, not the full file

append

Append content to an existing file

write_file

Write (create or overwrite) a file; creates parent dirs automatically

create_directory

Create a directory tree (mkdir -p semantics)

move_file

Move or rename a file within root

shell_exec

Run a whitelisted command — grep sed awk find cat head tail wc sort uniq cut tr diff file stat ls du rg

Full reference: docs/tools.md


Bring your own MCP

Chisel ships two embeddable libraries alongside the standalone server. Neither carries any HTTP, MCP protocol, or async runtime dependency — drop them into your own server and own the transport entirely.

Package

What it is

Use it when

chisel-core

Pure Rust sync library — path confinement, all file ops, shell exec

Writing a Rust MCP server

chisel-wasm

chisel-core compiled to wasm32-wasip1

Writing an MCP server in Node.js, Python, Deno, or any WASI runtime

Full integration guide → chisel-core/README.md


Standalone usage

Binary

Option A — Download pre-built binary (recommended)

Go to the latest release and download the binary for your platform:

Platform

File

macOS Apple Silicon

chisel-macos-arm64

macOS Intel

chisel-macos-x86_64

Linux x86-64

chisel-linux-x86_64

Linux ARM64

chisel-linux-arm64

# Make executable and run
chmod +x chisel-macos-arm64          # adjust filename for your platform
MCP_APP_SECRET=mysecret ./chisel-macos-arm64 --root /path/to/data

Option B — Build from source

cargo build --release -p chisel

Running

# Secret via env var (preferred)
MCP_APP_SECRET=mysecret ./chisel --root /path/to/data

# Or via --secret flag (env var takes precedence if both set)
./chisel --root /path/to/data --secret mysecret

# Read-only mode (shell_exec still works; writes are blocked)
MCP_APP_SECRET=mysecret ./chisel --root /path/to/data --read-only

The server binds to 127.0.0.1:3000 by default. Use --port to change the port.

Docker

Three ways to run Chisel in Docker — pick the one that fits your workflow.

# 1. Create your .env
echo "MCP_APP_SECRET=changeme" > .env

# 2. Create the data directory that will be exposed to the LLM
mkdir -p data

# 3. Start (builds the image on first run, then stays running)
docker compose up -d

# Tail logs
docker compose logs -f

# Stop
docker compose down

docker-compose.yml mounts ./data/data inside the container and binds 127.0.0.1:3000:3000 — the port is never exposed beyond localhost.

Option 2 — docker run

# Build
docker build -t chisel:latest .

# Run (replace /absolute/path/to/data with your actual data directory)
docker run -d \
  --name chisel \
  -e MCP_APP_SECRET=changeme \
  -v /absolute/path/to/data:/data \
  -p 127.0.0.1:3000:3000 \
  --restart unless-stopped \
  chisel:latest

# Read-only mode (writes blocked, shell_exec still works)
docker run -d \
  --name chisel \
  -e MCP_APP_SECRET=changeme \
  -v /absolute/path/to/data:/data:ro \
  -p 127.0.0.1:3000:3000 \
  chisel:latest chisel --root /data --read-only

Option 3 — Custom port

docker run -d \
  --name chisel \
  -e MCP_APP_SECRET=changeme \
  -v /absolute/path/to/data:/data \
  -p 127.0.0.1:8080:3000 \
  chisel:latest

Host port 8080 maps to container port 3000. Update your MCP client URL to http://127.0.0.1:8080/mcp accordingly.

The container runs as a non-root user (chisel) and never binds on 0.0.0.0. For remote access, place Caddy or nginx in front — see Behind a reverse proxy.

Configure your MCP client

{
  "mcpServers": {
    "chisel": {
      "url": "http://127.0.0.1:3000/mcp",
      "headers": {
        "Authorization": "Bearer <your-secret>"
      }
    }
  }
}

Behind a reverse proxy (Caddy)

Chisel deliberately refuses to bind on 0.0.0.0. Remote or multi-client access goes through a reverse proxy that handles TLS.

Caddy — automatic HTTPS

mcp.yourdomain.com {
    reverse_proxy 127.0.0.1:3000
}

Caddy auto-provisions a Let's Encrypt certificate. The bearer token still authenticates every request end-to-end.

# Install Caddy (macOS)
brew install caddy

# Run
caddy run --config Caddyfile

Your MCP client URL becomes https://mcp.yourdomain.com/mcp.

nginx

server {
    listen 443 ssl;
    server_name mcp.yourdomain.com;

    ssl_certificate     /etc/letsencrypt/live/mcp.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/mcp.yourdomain.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
    }
}

Extending chisel

See chisel-core/README.md for the full integration guide covering:

  • Rust API reference with code examples

  • spawn_blocking pattern for async handlers

  • Node.js (≥ 22) WASM / WASI integration

  • Python (wasmtime-py) WASM integration

  • Error types and security properties


Workspace layout

chisel/
├── chisel/          # HTTP server binary (MCP Streamable HTTP transport)
├── chisel-core/     # Portable sync library — no HTTP, no async, no MCP protocol
└── chisel-wasm/     # wasm32-wasip1 build of chisel-core for Node.js / Python / Deno
graph TD
    A[LLM / MCP client] -->|HTTP + Bearer| B[chisel binary]
    B --> C[chisel-core]
    D[Your Rust MCP server] --> C
    E[Node.js MCP server] -->|WASI| F[chisel-wasm .wasm]
    G[Python MCP server] -->|WASI| F
    F --> C

Security model

Security properties are split across two layers. Each row is verified by the test suite referenced at the bottom of this section.

chisel — MCP server / HTTP layer

#

Property

Mechanism

Default

1

Bearer-token auth — every request authenticated

subtle::ConstantTimeEq; timing-safe comparison; missing or empty secret → process exits at startup

required

2

Rate limiting — brute-force and runaway-agent protection

governor token-bucket; excess requests → HTTP 429 before auth is checked

100 req/s

3

Request body cap — memory exhaustion prevention

axum::DefaultBodyLimit; oversized body → HTTP 413 before any parsing

4 MiB

4

Audit log — every tool op traceable

tracing::info on success, tracing::warn on failure; records op name, path, error

info

5

Loopback-only binding — no accidental public exposure

TcpListener::bind("127.0.0.1:<port>"); 0.0.0.0 is never used

chisel-core — portable library (enforced on every op, including embedded use)

#

Property

Mechanism

6

Kernel-enforced root confinement — directory traversal, symlink escape, TOCTOU all blocked

cap_std::fs::Dir; every path component traversed via openat(fd, component, O_NOFOLLOW); confinement is enforced at the kernel level during I/O, not in userspace before it

7

Atomic writes — failed patch never corrupts the target file

Dir::create(".name.PID.tmp") + Dir::rename(tmp → target); both ops confined inside the same root fd; on any failure the tmp file is discarded and the original is untouched

8

Read-only mode — blanket write protection

check_writable(read_only) runs before any I/O inside every write op; no code path bypasses it

9

Shell whitelist + direct execve — no injection, no arbitrary commands

Fixed compile-time whitelist; std::process::Command spawns directly (no sh -c); path-like args validated via validate_path before spawn

graph LR
    req[Incoming request] --> body{Body ≤ limit?\nDefaultBodyLimit}
    body -- too large --> 413[HTTP 413]
    body -- ok --> rate{Rate limit\ntoken-bucket}
    rate -- exceeded --> 429[HTTP 429]
    rate -- ok --> auth{Bearer token\nconstant-time compare}
    auth -- reject --> 401[HTTP 401]
    auth -- pass --> path{Path confinement\ncap-std openat + O_NOFOLLOW}
    path -- outside root --> err[OutsideRoot error]
    path -- inside root --> ro{Read-only mode?}
    ro -- write op --> readonly[ReadOnly error]
    ro -- read / shell --> exec[Execute tool]
    exec --> audit[Audit log\ntracing::info/warn]
    exec --> atomic[Atomic write\nDir::create + Dir::rename]

Attack and misuse prevention

Each layer targets a specific class of failure — accidental or deliberate.

1. Authentication — unauthorised access

Every HTTP request must carry Authorization: Bearer <secret>. The comparison uses subtle::ConstantTimeEq, which takes the same number of CPU cycles regardless of how many characters match. A timing-based brute-force attack that probes the token character-by-character cannot succeed because no timing signal leaks.

The server refuses to start if the secret is empty or absent — misconfiguration is a hard error, not a silent fallback to no auth.

2. Path confinement — escape from root directory

This is the core guarantee. All filesystem tools (patch_apply, append, write_file, create_directory, move_file) operate exclusively through a cap_std::fs::Dir handle rooted at the configured root directory.

input string
  → strip root prefix → relative path
  → cap_std::fs::Dir::open / write / rename …
       └─ kernel: openat(root_fd, "sub/file", O_NOFOLLOW)
                  openat(sub_fd,  "file",     O_NOFOLLOW)

Every component of the path is traversed via openat with O_NOFOLLOW. The kernel enforces confinement — no userspace prefix check can be bypassed:

Attack

Example input

What happens

Directory traversal

/data/sub/../../etc/passwd

.. components tracked per-fd; escape above root blocked by kernel → error

Absolute path bypass

/etc/hosts

Root prefix stripped; remaining path confined to root fd → OutsideRoot

Symlink in component

/data/link/file where link → /etc

O_NOFOLLOW on link open → kernel rejects → error

TOCTOU swap

Valid path at check time, swapped to symlink before I/O

No separate check/use window — confinement is enforced during the I/O itself

validate_path (the userspace canonicalize + prefix check from earlier versions) is still used exclusively for shell_exec path arguments, where we pass strings to spawned processes that cap-std cannot confine.

3. Shell injection — arbitrary command execution

shell_exec does not invoke a shell interpreter. It calls std::process::Command directly with the command and arguments as separate OS-level strings:

shell_exec("grep", ["-r", "foo", "/data"])
  → execve("/usr/bin/grep", ["-r", "foo", "/data"])   ← no sh -c wrapper

Shell metacharacters (;, &&, |, $(), backticks, etc.) in any argument are passed as literal bytes to the target process. There is no shell to interpret them.

A fixed compile-time whitelist (grep sed awk find cat head tail wc sort uniq cut tr diff file stat ls du rg) is checked before the process is spawned. Any command not on the list returns CommandNotAllowed immediately — the process is never started.

Path-like arguments (starting with / or containing ..) are validated against root via validate_path before the process starts.

4. Partial write — file corruption on failed patch

patch_apply never writes directly to the target file. The flow is entirely confined within the cap-std Dir:

1. Parse and validate the diff
2. Dir::create(".filename.PID.tmp")   ← confined temp file, same directory
3. On success  → Dir::rename(tmp, target)   ← single syscall, cannot be interrupted mid-write
4. On failure  → return PatchFailed, tmp is dropped and cleaned up

If the hunk context does not match the current file (the file has drifted since the diff was generated), the operation aborts at step 1 and the original file is never touched. A process crash between steps 2 and 3 leaves the .tmp file — the original is still intact.

5. Read-only mode — blanket write protection

Starting with --read-only causes all five write tools (patch_apply, append, write_file, create_directory, move_file) to return ReadOnly immediately without performing any I/O. The check happens inside chisel-core before any disk access — there is no code path that bypasses it.

shell_exec remains available in read-only mode because it only reads (whitelisted commands are all inspection tools; mkdir and mv are explicitly excluded from the whitelist).

6. Rate limiting — brute-force and runaway-agent protection

Every request passes through a token-bucket rate limiter (governor) before authentication. When the configured rate (default: 100 req/s) is exceeded, the server immediately returns HTTP 429 Too Many Requests without doing any work.

This prevents two threat classes:

  • Token brute-force: an attacker cannot enumerate tokens faster than the configured rate, even with a leaked secret in partial form.

  • Runaway agent loops: a malfunctioning LLM client flooding the server is throttled before it can cause resource exhaustion.

Configure with --rate-limit <N> (or set to 0 to disable). The limiter is the outermost layer — requests that exceed the rate never reach the auth check.

7. Request body cap — memory exhaustion prevention

All incoming request bodies are capped at 4 MiB by default (DefaultBodyLimit). An oversized body is rejected before any parsing, authentication, or tool dispatch occurs.

Configure with --body-limit <bytes>. For typical LLM usage (unified diffs and file content), 4 MiB is generous — increase only if you intentionally send large file writes.

8. Audit logging — operation traceability

Every tool invocation emits a structured tracing log line recording the operation name, the target path (or command), and whether it succeeded or failed:

INFO chisel::tools::filesystem op=patch_apply path=/data/foo.txt
WARN chisel::tools::filesystem op=write_file  path=/etc/passwd error=OutsideRoot { ... }
INFO chisel::tools::shell       op=shell_exec cmd=grep exit_code=0

Log verbosity is controlled via the RUST_LOG environment variable (e.g. RUST_LOG=chisel=debug). The default level is info, which captures every tool call result without flooding output with framework internals.

9. Network exposure — no accidental public binding

The server calls TcpListener::bind("127.0.0.1:<port>") — not 0.0.0.0. It is impossible for the process itself to accept connections from outside the machine. Remote access must be deliberately routed through a reverse proxy (Caddy, nginx), which is where TLS termination and any additional access controls live.

The Docker image runs as a non-root user (mcp) and the docker-compose.yml maps the port as 127.0.0.1:3000:3000, preserving the loopback restriction even inside a container.

Security test coverage

Every property above is verified by a dedicated test suite at [chisel/tests/security.rs](chisel/tests/security.rs). Run with cargo test --test security -p chisel.

Property

Tests

§1 Authentication

auth_missing_secret_is_hard_error · auth_empty_secret_is_hard_error · auth_missing_header_returns_401 · auth_wrong_token_returns_401 · auth_basic_scheme_returns_401 · auth_prefix_of_secret_returns_401 · auth_valid_token_passes

§2 Path confinement

path_directory_traversal_is_blocked · path_absolute_outside_root_returns_outside_root_error · path_symlink_in_component_is_blocked · path_toctou_symlink_swap_is_blocked · path_deeply_nested_outside_root_is_blocked

§3 Shell injection

shell_dangerous_commands_blocked_before_spawn · shell_metacharacters_are_literal · shell_path_arg_outside_root_blocked_before_spawn · shell_traversal_in_arg_blocked_before_spawn

§4 Partial write

partial_write_failed_patch_leaves_file_intact · partial_write_no_tmp_artefact_on_failure

§5 Read-only mode

readonly_all_write_tools_are_blocked · readonly_shell_exec_remains_available · readonly_no_disk_mutation_occurs

§6 Network binding

network_bind_address_is_loopback_only · network_sse_endpoint_returns_404

All 23 tests pass on every CI run. A failure means a documented security guarantee has regressed.

$ cargo test --test security -p chisel
running 23 tests
test auth_empty_secret_is_hard_error ... ok
test auth_missing_secret_is_hard_error ... ok
test network_bind_address_is_loopback_only ... ok
test path_absolute_outside_root_returns_outside_root_error ... ok
test path_deeply_nested_outside_root_is_blocked ... ok
test readonly_all_write_tools_are_blocked ... ok
test readonly_no_disk_mutation_occurs ... ok
test path_directory_traversal_is_blocked ... ok
test shell_dangerous_commands_blocked_before_spawn ... ok
test shell_path_arg_outside_root_blocked_before_spawn ... ok
test path_symlink_in_component_is_blocked ... ok
test shell_traversal_in_arg_blocked_before_spawn ... ok
test partial_write_failed_patch_leaves_file_intact ... ok
test partial_write_no_tmp_artefact_on_failure ... ok
test path_toctou_symlink_swap_is_blocked ... ok
test readonly_shell_exec_remains_available ... ok
test shell_metacharacters_are_literal ... ok
test auth_missing_header_returns_401 ... ok
test auth_valid_token_passes ... ok
test auth_basic_scheme_returns_401 ... ok
test auth_prefix_of_secret_returns_401 ... ok
test auth_wrong_token_returns_401 ... ok
test network_sse_endpoint_returns_404 ... ok

test result: ok. 23 passed; 0 failed

Development

# Run all tests
cargo test --workspace

# Run only the server tests
cargo test -p chisel

# Build the WASM target
rustup target add wasm32-wasip1
cargo build --target wasm32-wasip1 -p chisel-wasm

# Build Docker image
docker build -t chisel:dev .

Platform support

Platform

Server binary (chisel)

chisel-core (lib, no shell)

chisel-wasm

Linux (x86_64, arm64)

✅ Full support

macOS (Apple Silicon, Intel)

✅ Full support

Windows

❌ Not supported

⚠️ Compiles, untested

Linux / macOS — primary targets. All nine security properties hold. Docker image is Debian-based. shell_exec whitelist (grep, sed, awk, find, cat, ls, …) assumes a standard Unix environment.

Windows — not supported for the server binary for three reasons:

  1. shell_exec whitelist is entirely Unix tools; most do not exist natively on Windows

  2. cap-std kernel confinement uses POSIX openat + O_NOFOLLOW semantics; Win32 reparse-point / junction handling differs

  3. Symlink creation requires elevated privileges (SeCreateSymbolicLinkPrivilege) — security tests cannot run without Administrator or Developer Mode

**chisel-wasm** — fully portable. WASM has no OS dependency; runs identically on any WASI-capable runtime (Node.js ≥ 22, Deno, Wasmtime) regardless of host OS. shell_exec is excluded from the WASM build.


Contributing

Contributions are welcome. A few guidelines:

  • Bug fixes and small improvements — open a PR directly.

  • New tools or behaviour changes — open an issue first to agree on scope before writing code.

  • Security issues — do not open a public issue. File a private report and include reproduction steps.

Before submitting:

cargo test --workspace          # all tests must pass
cargo test --test security -p chisel   # security suite must be green
cargo clippy --workspace -- -D warnings
cargo fmt --check

New security-relevant code should come with a matching test in chisel/tests/security.rs that names the exact attack vector it covers.


Future considerations

S3 / R2 object storage backend

A potential extension is a thin sync layer that hydrates S3 or R2 objects into a local scratch directory (RAM-backed or tmpfs), runs all Chisel operations against that directory through the normal chisel-core path, then flushes changed objects back on completion.

The agent would interact exclusively with Chisel — path confinement, atomic patching, and shell tooling all behave identically. S3/R2 would serve purely as the persistence layer, transparent to the model.

Open problems before this is viable: concurrent writes to the same object need optimistic locking (ETag-based check-and-swap on flush), and a native cap-std equivalent does not exist for object storage, so confinement must be enforced at the scratch directory level rather than the storage layer. The core shell_exec whitelist also assumes a Unix filesystem and would require the object to be fully materialized locally before any command runs.

Available Tools

6 tools
appendA

Append content to an existing file. Fails if file does not exist. Returns error in read-only mode.

ParametersJSON Schema
NameRequiredDescriptionDefault
contentYes
pathYes

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Discloses two important failure modes beyond the basic operation: file existence and read-only restrictions. With no annotations, this adds useful behavioral context, though other potential behaviors (e.g., encoding, size limits) are omitted.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences that are front-loaded with the core action, followed by key constraints. Every word adds value with zero redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Covers the main behavior and two error scenarios, but lacks information on return values (success indicator, appended content?) and potential limitations (max file size, binary vs text). Given no output schema, some feedback on success would improve completeness.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Parameters (content, path) are self-explanatory given the tool purpose, but the description adds no extra meaning beyond the schema. With 0% schema description coverage, baseline is 3; no improvement or detriment.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description specifies the action (append content), the target (existing file), and failure conditions (file missing, read-only mode). It clearly distinguishes from siblings like write_file (which can create/overwrite) and create_directory.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Indicates when to use (appending to existing files) and when it fails (non-existent file, read-only), guiding against misuse. However, lacks explicit alternatives or comparison with sibling tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

create_directoryC

Create a directory (including parents). Returns error in read-only mode.

ParametersJSON Schema
NameRequiredDescriptionDefault
pathYes

TDQS

C2.7/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description must disclose all behavioral traits. It only mentions error in read-only mode. Missing: behavior if directory exists, return value, permission requirements, or side effects beyond directory creation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single short sentence, which is compact. However, it sacrifices necessary detail for brevity, making it under-specified. It is not as concise as it could be if it included key behavioral points.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple 1-parameter tool with no output schema and no annotations, the description is incomplete. It covers creation and parent directory creation but omits critical context like handling of existing directories, success/error responses, and potential side effects.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters1/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The sole parameter 'path' has no description in the schema (0% coverage). The tool description adds no additional meaning, such as format, relative vs absolute, or allowed characters, leaving the agent with only the raw name 'path'.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description explicitly states the action ('create a directory') and resource ('directory'), and adds that it includes parent directories. This clearly distinguishes it from sibling file operations like append, move_file, write_file.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance on when to use this tool versus alternatives (e.g., write_file for file creation). The only usage hint is 'Returns error in read-only mode,' which is a condition, not a comparison with other tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

move_fileC

Move or rename a file within the root directory. Returns error in read-only mode.

ParametersJSON Schema
NameRequiredDescriptionDefault
destinationYes
sourceYes

TDQS

C2.7/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description mentions 'Returns error in read-only mode', which is a behavioral trait. However, with no annotations, the description should disclose more about side effects, overwrite behavior, or permissions, which it does not.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is very short and front-loaded but may be too brief. It is concise but at the cost of omitting important details.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the lack of output schema and schema descriptions, the description misses essential context like path formats, overwrite behavior, and atomicity. It is insufficient for a mutation tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters1/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, and the description does not explain the parameters (source, destination). It leaves their meaning and format entirely implicit, failing to compensate for the lack of schema descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action (move or rename) and the scope (within root directory). It distinguishes from sibling tools like write_file or append, which have different purposes.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No explicit guidance on when to use this tool versus alternatives. The description implies root directory usage but does not mention when not to use it or provide context on renaming vs moving.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

patch_applyA

Apply a unified diff patch to a file. Accepts markdown-fenced diffs. Use --- /dev/null to create new files. Returns error in read-only mode.

ParametersJSON Schema
NameRequiredDescriptionDefault
patchYesUnified diff to apply (may be wrapped in a markdown code fence)
pathYesAbsolute path to the file to patch

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden. It discloses that the tool modifies files, accepts markdown-fenced diffs, can create new files, and returns an error in read-only mode. This provides meaningful behavioral context beyond the schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description consists of three concise sentences, each adding essential information. No redundant or vague language; every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool has two parameters, no output schema, and no annotations, the description adequately covers the purpose, input format, special usage, and error condition. It is missing details on return value on success, but overall is sufficiently complete for an AI agent to use correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Input schema descriptions cover both parameters (100% coverage). The tool description adds additional semantics for the 'patch' parameter by specifying that diffs may be wrapped in a markdown code fence, which goes beyond the schema description. Thus, it adds value.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description clearly states it applies a unified diff patch to a file, specifying input format and special case for creating new files. This distinguishes it from sibling tools (append, create_directory, move_file, shell_exec, write_file) which perform different operations.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context on when to use the tool (applying patches) and includes a specific usage hint for creating new files. It does not explicitly mention alternatives or exclusions, but sibling tools are distinct enough that no further guidance is necessary.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

shell_execA

Execute a whitelisted shell command (grep/cat/ls/find/sed/awk/…). No shell interpreter — args are passed literally. Path args validated against root.

ParametersJSON Schema
NameRequiredDescriptionDefault
argsYes
commandYes

TDQS

A3.8/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations present, so description must carry the burden. It discloses that there is no shell interpreter and that args are passed literally, and path validation occurs. However, it omits behavior on non-whitelisted commands, error handling, and output details.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is three sentences, no fluff, front-loaded with purpose. Each sentence adds essential information about what the tool does and its behavioral constraints.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the complexity of shell execution and lack of annotations or output schema, the description covers key constraints but misses return value format, sync/async behavior, and explicit failure modes. Adequate but incomplete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so description must compensate. It explains that 'args are passed literally' and 'path args validated against root' but does not clarify the structure of the args array or the acceptable values for command beyond examples. Insufficient detail for both parameters.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool executes whitelisted shell commands with examples (grep/cat/ls/find/sed/awk). It distinguishes from siblings which are file operations like append and write.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides guidance on when to use: for whitelisted shell commands, with literal argument passing and path validation. It does not explicitly exclude alternatives but gives clear constraints.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

write_fileA

Write content to a file (create or overwrite). Creates parent dirs. Returns error in read-only mode.

ParametersJSON Schema
NameRequiredDescriptionDefault
contentYes
pathYes

TDQS

A3.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Despite no annotations, the description discloses key behaviors: creates parent directories, returns error in read-only mode. This adds valuable context beyond the basic write operation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Extremely concise: three sentences, no fluff. First sentence front-loads the purpose. Every sentence adds meaningful information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple tool with two params and no output schema, the description covers the main behavior, directory creation, and error condition. Minor missing details like path format or content encoding, but adequate overall.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The description provides no information about the parameters beyond what the schema shows (path and content). With 0% schema coverage, the description should clarify format or constraints but fails to do so.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool writes content to a file, with create or overwrite semantics. It distinguishes from sibling tools like append (which appends) and create_directory (which creates directories).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No explicit guidance on when to use this tool versus alternatives like append or create_directory. The description only mentions behavior but not context of use.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.

  1. 6 tool updatesv0.1.2
    • Addedappend
    • Addedcreate_directory
    • Addedmove_file
    • Addedpatch_apply
    • Addedshell_exec
    • Addedwrite_file

TDQS

B3.4/5.0
Disambiguation5/5

Each tool has a clearly distinct purpose: file content operations (append, write, patch_apply), file/directory management (create_directory, move_file), and command execution (shell_exec). No two tools overlap in function.

Naming Consistency4/5

All tool names use snake_case and most follow a verb_noun pattern (e.g., create_directory, move_file, write_file). 'patch_apply' is a minor deviation (noun_verb), but overall the naming is predictable and readable.

Tool Count5/5

With 6 tools, the server is well-scoped for a file manipulation and shell execution purpose. Each tool serves a distinct role without unnecessary bloat.

Completeness2/5

The server covers write, append, move, patch, and directory creation, but lacks essential operations like file/directory deletion and explicit file reading. Although shell_exec can partially substitute for reading, the gap is notable for a file system toolset.

Maintenance

ActivityInactive
ResponsivenessUnresponsive

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    B
    maintenance
    Reduces token consumption by over 80% through intelligent file caching, returning only diffs for modified files and suppressing unchanged content. It features a suite of 12 tools for semantic search, batch reading, and efficient file editing to optimize LLM interactions with large codebases.
    13
    2
    MIT
  • A
    license
    A
    quality
    C
    maintenance
    MCP server that combines Read+Edit file operations into single tool calls. 80-95% fewer tool calls formulti-file refactoring across Claude, Cursor, Windsurf, and more.
    3
    21
    3
    MIT
  • A
    license
    B
    quality
    A
    maintenance
    Agent-optimized MCP server that replaces built-in file, search, exec, and git tools with compact, structured JSON equivalents. Benchmarked 20–45% token savings for AI coding agents.
    20
    2
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    An MCP server giving coding agents context-window-aware code search and safe, atomic multi-file edits — built to cut token usage on large codebases without sacrificing correctness.
    3
    132
    5
    MIT

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ckanthony/chisel'

If you have feedback or need assistance with the MCP directory API, please join our Discord server