2026-02-22 15:24:48 +00:00
2026-02-22 15:24:48 +00:00
2026-01-18 18:40:26 +00:00
2026-05-29 05:31:00 +01:00
2026-05-29 05:31:00 +01:00

mcp-filepuff

A Go-based MCP (Model Context Protocol) server for Claude Code providing intelligent file operations with fast search, AST-aware querying, LSP integration, and safe editing capabilities.

Features

  • Fast Text Search: Powered by ripgrep for blazing-fast code search with regex support
  • AST-Aware File Reading: Read files with symbol extraction using Tree-sitter
  • Code Pattern Matching: Query code using patterns with capture placeholders
  • LSP Integration: Go-to-definition, find references, and symbol info via language servers
  • Safe Editing: AST-aware file editing with syntax validation (edit_apply)
  • Multi-Language Support: Go, TypeScript, JavaScript, Python, C, C++, HTML, Vue, React
  • Token Efficient: Optimized for minimal token usage with symbols-only mode and output limiting

Installation

Install the latest version with a single command:

curl -sSL https://raw.githubusercontent.com/lukaszraczylo/filepuff-mcp/main/scripts/install.sh | bash

This script will:

  • Automatically detect your platform (OS and architecture)
  • Download the latest release
  • Verify checksums
  • Install to ~/.local/bin (or /usr/local/bin if needed)
  • Make the binary executable

Docker

docker pull ghcr.io/lukaszraczylo/filepuff-mcp:latest

The MCP server communicates over stdio. Mount your workspace and run with -i:

docker run -i --rm -v /path/to/workspace:/workspace ghcr.io/lukaszraczylo/filepuff-mcp:latest -workspace /workspace

Claude Code configuration (.claude/settings.json):

{
  "mcpServers": {
    "filepuff": {
      "command": "docker",
      "args": ["run", "-i", "--rm", "-v", ".:/workspace", "ghcr.io/lukaszraczylo/filepuff-mcp:latest", "-workspace", "/workspace"]
    }
  }
}

Manual Installation

Download pre-built binaries from the releases page:

# macOS (ARM64)
curl -L https://github.com/lukaszraczylo/filepuff-mcp/releases/latest/download/mcp-filepuff_<version>_darwin_arm64.tar.gz | tar xz
mv mcp-filepuff ~/.local/bin/

# macOS (AMD64)
curl -L https://github.com/lukaszraczylo/filepuff-mcp/releases/latest/download/mcp-filepuff_<version>_darwin_amd64.tar.gz | tar xz
mv mcp-filepuff ~/.local/bin/

# Linux (ARM64)
curl -L https://github.com/lukaszraczylo/filepuff-mcp/releases/latest/download/mcp-filepuff_<version>_linux_arm64.tar.gz | tar xz
mv mcp-filepuff ~/.local/bin/

# Linux (AMD64)
curl -L https://github.com/lukaszraczylo/filepuff-mcp/releases/latest/download/mcp-filepuff_<version>_linux_amd64.tar.gz | tar xz
mv mcp-filepuff ~/.local/bin/

# Windows (PowerShell)
Invoke-WebRequest -Uri "https://github.com/lukaszraczylo/filepuff-mcp/releases/latest/download/mcp-filepuff_<version>_windows_amd64.zip" -OutFile mcp-filepuff.zip
Expand-Archive mcp-filepuff.zip -DestinationPath $env:USERPROFILE\.local\bin

Replace <version> with the actual version (e.g., v1.0.0).

Prerequisites

  • ripgrep (rg) installed and in PATH

Optional Dependencies (for LSP features)

  • gopls - Go language server
  • typescript-language-server - TypeScript/JavaScript language server
  • pylsp - Python language server
  • clangd - C/C++ language server

Build from Source

git clone https://github.com/lukaszraczylo/filepuff-mcp.git
cd filepuff-mcp
make build

The binary will be available at bin/mcp-filepuff.

Install via Claude Code

After downloading or building the binary, configure it in Claude Code:

  1. Create or edit ~/.config/claude-code/claude_desktop_config.json:
{
  "mcpServers": {
    "filepuff": {
      "command": "/usr/local/bin/mcp-filepuff",
      "args": ["-workspace", "/path/to/your/workspace"],
      "env": {
        "MCP_LOG_LEVEL": "info"
      }
    }
  }
}
  1. Restart Claude Code to load the MCP server

  2. Verify by asking Claude: "Can you ping the filepuff server?"

See the Claude Code MCP documentation for more details.

Selective Tool Deferral

For optimal performance, keep the most frequently used tools loaded at startup and defer the rest. This follows Anthropic's recommended practice of loading 3-5 high-use tools immediately:

{
  "mcpServers": {
    "filepuff": {
      "command": "mcp-filepuff",
      "args": ["-workspace", "."],
      "alwaysAllow": ["file_read", "file_search", "edit_apply"]
    }
  }
}

This keeps file_read, file_search, and edit_apply immediately available while deferring less frequently used tools (ping, ast_query, symbol_at, find_definition, find_references).

System Prompt Guidance

Add the following to your CLAUDE.md to help Claude understand the available tool categories:

You have access to filepuff MCP tools providing:
- File reading with AST symbol summaries (file_read)
- Fast regex search powered by ripgrep (file_search)
- Structural code pattern matching across 9+ languages (ast_query)
- LSP-powered go-to-definition, find-references, and symbol info (find_definition, find_references, symbol_at)
- AST-aware file editing with syntax validation (edit_apply)

Usage

Running the Server (Standalone)

./bin/mcp-filepuff -workspace /path/to/workspace

Command Line Options

  • -workspace string: Workspace root directory (default: current directory)
  • -log-level string: Log level - debug, info, warn, error (default: "info")
  • -log-file string: Log file path (default: stderr)

Configuration

The server can be configured via:

  1. Environment Variables:

    • MCP_WORKSPACE_ROOT: Workspace root directory
    • MCP_LSP_TIMEOUT: LSP timeout duration (e.g., "10m")
    • MCP_SEARCH_TIMEOUT: Search timeout duration (e.g., "1m")
    • MCP_ENABLE_LSP: Enable LSP features ("true"/"false")
    • MCP_FOLLOW_SYMLINKS: Follow symbolic links ("true"/"false")
    • MCP_RESPECT_GITIGNORE: Respect .gitignore files ("true"/"false")
  2. Config File: Create .mcp-filepuff.json in the workspace root:

    {
      "enable_lsp": true,
      "follow_symlinks": true,
      "respect_gitignore": true
    }
    

Claude Code Integration

To use mcp-filepuff with Claude Code, add it to your MCP server configuration:

  1. Global Configuration (~/.config/claude-code/mcp_servers.json):

    {
      "mcpServers": {
        "filepuff": {
          "command": "/path/to/mcp-filepuff",
          "args": ["-workspace", "/path/to/your/workspace"]
        }
      }
    }
    
  2. Project-specific Configuration (.claude/mcp_servers.json in your project):

    {
      "mcpServers": {
        "filepuff": {
          "command": "mcp-filepuff",
          "args": ["-workspace", "."]
        }
      }
    }
    

After configuration, Claude Code will have access to all mcp-filepuff tools for enhanced file operations.

Making Claude Code Prefer Filepuff Tools

By default, Claude Code uses its built-in file operation tools. To make it prefer filepuff's enhanced tools, add instructions to your CLAUDE.md file:

Global Configuration (~/.claude/CLAUDE.md):

# MCP Tool Preferences

When performing file operations, prefer filepuff MCP tools over built-in equivalents:

| Operation | Use This | Instead Of |
|-----------|----------|------------|
| Read files | `mcp__filepuff__file_read` | Read |
| Search content | `mcp__filepuff__file_search` | Grep |
| AST pattern search | `mcp__filepuff__ast_query` | Grep/Glob |
| Edit files | `mcp__filepuff__edit_apply` | Edit |
| Find definitions | `mcp__filepuff__find_definition` | Grep |
| Find references | `mcp__filepuff__find_references` | Grep |
| Symbol info | `mcp__filepuff__symbol_at` | - |

Benefits of filepuff tools:
- AST-aware operations that understand code structure
- LSP integration for accurate symbol navigation
- Syntax validation before applying edits

You can also place this in a project-specific CLAUDE.md or .claude/CLAUDE.md file.

Optional: Restrict Built-in Tools

To enforce filepuff usage, add permission restrictions in .claude/settings.json:

{
  "permissions": {
    "deny": ["Read", "Edit", "Grep"]
  }
}

Available Tools

ping

Health check tool to verify the server is running.

Returns: "pong"


Search for text patterns in files using ripgrep.

Parameters:

  • pattern (required): The search pattern (regex by default)
  • paths: Paths to search in (defaults to workspace root)
  • file_types: File types to search (e.g., ["go", "ts", "py"])
  • ignore_case: Case insensitive search
  • regex: Treat pattern as regex (default: true)
  • context_lines: Number of context lines around matches (default: 2)
  • max_results: Maximum number of results to return

file_read

Read a file's contents with optional line range and AST symbol summary. Supports token-efficient modes for AI assistants.

Parameters:

  • path (required): Path to the file to read
  • line_start: Starting line number (1-indexed)
  • line_end: Ending line number (inclusive)
  • include_ast: Include AST symbol summary (functions, classes, types, etc.)
  • symbols_only: [Token Efficient] Return only symbol summary without file content. Requires include_ast=true. Reduces token usage by ~90-98%.
  • max_lines: [Token Efficient] Maximum number of lines to return. Useful for large files where you only need a preview.

Example Output with AST:

**server.go** (245 lines, go)

Symbols:
  func NewServer  L12
  func (Server).Start  L45
  struct Server  L5
  type Config  L150

---

   12│ func NewServer(config Config) *Server {
   13│     return &Server{config: config}
   14│ }

Token-Efficient Example (symbols_only):

{"path": "server.go", "include_ast": true, "symbols_only": true}

Returns only the symbol summary (~500 tokens instead of ~8,000 tokens for the full file):

**server.go** (245 lines, go)

Symbols:
  func NewServer  L12
  func (Server).Start  L45
  struct Server  L5
  type Config  L150

Token-Efficient Example (max_lines):

{"path": "server.go", "max_lines": 50}

Returns first 50 lines with a truncation notice if the file is longer.


ast_query

Search for AST patterns in code files using structural pattern matching.

Parameters:

  • pattern (required): Code pattern with placeholders
    • $NAME - capture single node
    • $$$ARGS - capture multiple nodes
    • $_ - wildcard (match but don't capture)
  • language (required): Target language (go, typescript, javascript, python, c, cpp)
  • paths: Paths to search in
  • name_matches: Regex pattern to filter by name
  • name_exact: Exact name to match
  • kind_in: Node types to match (e.g., function_declaration)
  • max_results: Maximum number of results (default: 100)

Examples:

// Find all Go functions returning error
{"pattern": "func $NAME($$$ARGS) error", "language": "go"}

// Find all Python classes
{"pattern": "class $NAME: $$$BODY", "language": "python"}

// Find React components (functions starting with uppercase)
{"pattern": "function $NAME($PROPS) { $$$BODY }", "language": "javascript", "name_matches": "^[A-Z]"}

symbol_at

Get information about the symbol at a specific position. Uses LSP when available, falls back to AST.

Parameters:

  • file (required): Path to the file
  • line (required): Line number (1-indexed)
  • column (required): Column number (1-indexed)

find_definition

Find the definition of the symbol at a specific position.

Parameters:

  • file (required): Path to the file
  • line (required): Line number (1-indexed)
  • column (required): Column number (1-indexed)

find_references

Find all references to the symbol at a specific position.

Parameters:

  • file (required): Path to the file
  • line (required): Line number (1-indexed)
  • column (required): Column number (1-indexed)
  • include_declaration: Include the declaration in results (default: true)

edit_apply

Apply an edit to a file. Uses AST-aware editing for code files with syntax validation, and text-based editing for other files.

Parameters:

  • file (required): Path to the file to edit
  • operation (required): Edit operation (replace, insert_before, insert_after, delete)
  • new_content: New content (required for replace/insert operations)

AST-mode selectors (for code files):

  • selector_kind: Node type to match (e.g., function_declaration)
  • selector_name: Name of the symbol to match

Shared selectors:

  • selector_line: Line number (1-indexed). For AST mode: narrows search. For text mode: start of line range.
  • selector_index: Index of the match to use if multiple matches found (default: 0)

Text-mode selectors (for non-code files or explicit text matching):

  • selector_line_end: End line number for range selection
  • selector_text: Exact text to match (must be unique or use selector_index)
  • selector_pattern: Regex pattern to match

Example (AST mode - Go file):

{
  "file": "server.go",
  "operation": "replace",
  "selector_kind": "function_declaration",
  "selector_name": "Hello",
  "new_content": "func Hello() {\n\tprintln(\"New Hello\")\n}"
}

Example (Text mode - Markdown file):

{
  "file": "README.md",
  "operation": "replace",
  "selector_text": "## Installation",
  "new_content": "## Getting Started"
}

Example (Text mode - JSON with regex):

{
  "file": "package.json",
  "operation": "replace",
  "selector_pattern": "\"version\":\\s*\"[^\"]+\"",
  "new_content": "\"version\": \"2.0.0\""
}

Example (Text mode - Line range):

{
  "file": "config.yaml",
  "operation": "replace",
  "selector_line": 5,
  "selector_line_end": 10,
  "new_content": "database:\n  host: production.db.example.com\n  port: 5432"
}

Supported Languages

Language Extensions Search AST LSP Edit
Go .go Yes Yes gopls Yes
TypeScript .ts, .tsx Yes Yes typescript-language-server Yes
JavaScript .js, .jsx, .mjs, .cjs Yes Yes typescript-language-server Yes
Python .py, .pyw Yes Yes pylsp Yes
C .c, .h Yes Yes clangd Yes
C++ .cpp, .cc, .cxx, .hpp, .hxx Yes Yes clangd Yes
HTML .html, .htm Yes Yes - Yes
Vue .vue Yes Yes* - Yes
React .jsx, .tsx Yes Yes typescript-language-server Yes
Elixir .ex, .exs Yes Yes elixir-ls Yes

* Vue uses HTML parser for template sections

Development

Build

make build

Run Tests

make test

Lint

make lint

Clean

make clean

Project Structure

.
├── cmd/
│   └── mcp-filepuff/       # Main entry point
├── internal/
│   ├── config/             # Configuration management
│   ├── edit/               # AST-aware editing engine
│   ├── lsp/                # LSP client and manager
│   ├── parser/             # Tree-sitter integration
│   ├── query/              # AST pattern matching
│   ├── search/             # Ripgrep wrapper
│   └── server/             # MCP server implementation
├── pkg/
│   └── protocol/           # Shared types
├── .github/
│   └── workflows/          # CI configuration
├── Makefile               # Build automation
├── .goreleaser.yaml       # Release configuration
└── TODO.md                # Implementation roadmap

Architecture

High-Level Overview

┌─────────────────────────────────────────────────────────┐
│                    MCP Server                           │
├─────────────────────────────────────────────────────────┤
│  Tools: file_search, file_read, ast_query, symbol_at,  │
│         find_definition, find_references, edit_apply, ping                 │
├─────────────────────────────────────────────────────────┤
│                    Core Engines                         │
├───────────┬─────────────┬────────────┬─────────────────┤
│  Search   │   Parser    │    LSP     │     Edit        │
│ (ripgrep) │(tree-sitter)│  Manager   │    Engine       │
└───────────┴─────────────┴────────────┴─────────────────┘

Detailed Sequence Diagrams

LSP Integration Flow

The following diagram shows how LSP requests (hover, definition, references) flow through the system:

sequenceDiagram
    participant Client as MCP Client
    participant Server as MCP Server
    participant LSPMgr as LSP Manager
    participant LSPSrv as LSP Server (gopls/etc)
    participant FS as File System
    
    Client->>Server: symbol_at(file, line, col)
    activate Server
    
    Server->>LSPMgr: GetServer(language)
    activate LSPMgr
    
    alt Server Not Running
        LSPMgr->>LSPSrv: Start Process
        LSPMgr->>LSPSrv: initialize request
        LSPSrv-->>LSPMgr: capabilities
        LSPMgr->>LSPSrv: initialized notification
    end
    
    LSPMgr-->>Server: ManagedServer
    deactivate LSPMgr
    
    Server->>LSPMgr: ensureDocumentOpen(file)
    activate LSPMgr
    
    alt Document Not Open
        LSPMgr->>FS: ReadFile(path)
        FS-->>LSPMgr: content
        LSPMgr->>LSPSrv: textDocument/didOpen
    end
    
    LSPMgr-->>Server: ready
    deactivate LSPMgr
    
    Server->>LSPSrv: textDocument/hover
    activate LSPSrv
    LSPSrv-->>Server: HoverResult
    deactivate LSPSrv
    
    Server-->>Client: Symbol information
    deactivate Server

Edit Operation Flow

The edit engine uses atomic writes and validation to ensure safe file modifications:

sequenceDiagram
    participant Client as MCP Client
    participant Server as MCP Server
    participant Edit as Edit Engine
    participant Parser as Parser Registry
    participant FS as File System
    
    Client->>Server: edit_apply(file, operation, selector, content)
    activate Server
    
    Server->>Edit: Apply(ctx, edit)
    activate Edit
    
    Edit->>Edit: lockFile(path)
    Note over Edit: Per-file mutex prevents<br/>concurrent edits
    
    Edit->>FS: ReadFile(path)
    FS-->>Edit: original content
    
    alt AST-Aware Mode (code files)
        Edit->>Parser: Parse(ctx, path, content)
        activate Parser
        Parser-->>Edit: ParseResult with AST
        deactivate Parser
        
        Edit->>Edit: resolveSelector(selector, tree)
        Note over Edit: Find target node by<br/>kind, name, line, index
        
        Edit->>Edit: applyEdit(operation, node, content)
        Note over Edit: Apply replace/insert/delete<br/>with indentation preservation
        
        Edit->>Parser: Parse(ctx, path, newContent)
        activate Parser
        Parser-->>Edit: Validate syntax
        deactivate Parser
        
        alt Syntax Error
            Edit-->>Server: ValidationError
            Server-->>Client: Error: invalid syntax
        end
    else Text Mode (non-code files)
        Edit->>Edit: resolveTextSelector(selector)
        Note over Edit: Find by text, pattern,<br/>or line range
        
        Edit->>Edit: applyTextEditOperation
    end
    
    Edit->>Edit: generateDiff(original, new)
    
    Edit->>FS: Stat(path) - get permissions
    Edit->>FS: WriteFile(path, content, perm)
    Note over Edit,FS: Atomic write preserves<br/>original permissions
    
    Edit->>Edit: unlockFile(path)
    
    Edit-->>Server: EditResult{Success, Diff}
    deactivate Edit
    
    Server-->>Client: Success + Diff
    deactivate Server

Parse and Cache Flow

The parser uses content-based caching for efficient AST reuse:

sequenceDiagram
    participant Client as MCP Client
    participant Server as MCP Server
    participant Parser as Parser Registry
    participant Cache as LRU Cache
    participant TS as Tree-sitter
    
    Client->>Server: file_read(path, include_ast=true)
    activate Server
    
    Server->>Parser: Parse(ctx, path, content)
    activate Parser
    
    Parser->>Parser: contentHash(content)
    Note over Parser: xxHash64 for fast<br/>content fingerprinting
    
    Parser->>Cache: Get(hash)
    activate Cache
    
    alt Cache Hit
        Cache-->>Parser: CachedTree
        Parser->>Parser: cacheHits++
        Note over Parser: ~100x faster than parsing
    else Cache Miss
        Cache-->>Parser: nil
        deactivate Cache
        Parser->>Parser: cacheMisses++
        
        Parser->>Parser: GetParser(language)
        Note over Parser: One parser per language,<br/>reused across requests
        
        Parser->>TS: ParseCtx(ctx, content)
        activate TS
        Note over TS: Tree-sitter parsing<br/>with timeout support
        TS-->>Parser: *sitter.Tree
        deactivate TS
        
        Parser->>Cache: Add(hash, tree)
        activate Cache
        Note over Cache: LRU eviction when<br/>capacity reached (100 entries)
        Cache-->>Parser: stored
        deactivate Cache
    end
    
    Parser->>Parser: extractErrors(tree)
    Parser->>Parser: ExtractSymbols(tree)
    
    Parser-->>Server: ParseResult{Tree, Language, Errors, Symbols}
    deactivate Parser
    
    Server->>Server: generateASTSummary()
    Server-->>Client: File content + Symbol summary
    deactivate Server

Request Flow Summary

flowchart TB
    subgraph "MCP Protocol Layer"
        A[MCP Client] --> B[MCP Server]
    end
    
    subgraph "Tool Handlers"
        B --> C{Tool Type}
        C -->|Search| D[file_search]
        C -->|Read| E[file_read]
        C -->|Query| F[ast_query]
        C -->|LSP| G[symbol_at<br/>find_definition<br/>find_references]
        C -->|Edit| H[edit_apply]
    end
    
    subgraph "Core Engines"
        D --> I[Search Engine<br/>ripgrep]
        E --> J[Parser Registry]
        F --> J
        F --> K[Query Matcher]
        G --> L[LSP Manager]
        H --> M[Edit Engine]
        M --> J
    end
    
    subgraph "External Systems"
        I --> N[(File System)]
        J --> O[Tree-sitter]
        J --> P[(Parse Cache)]
        L --> Q[gopls<br/>typescript-language-server<br/>pylsp<br/>clangd]
        M --> N
    end

Troubleshooting

Common Issues

"ripgrep not found" Error

The file_search tool requires ripgrep (rg) to be installed and in your PATH.

Solution: Install ripgrep:

# macOS
brew install ripgrep

# Ubuntu/Debian
sudo apt install ripgrep

# Windows (with Chocolatey)
choco install ripgrep

LSP Features Not Working

LSP features (go-to-definition, find-references, symbol-at) require language servers to be installed.

Solution: Install the appropriate language server:

# Go
go install golang.org/x/tools/gopls@latest

# TypeScript/JavaScript
npm install -g typescript-language-server typescript

# Python
pip install python-lsp-server

# C/C++
# macOS: brew install llvm
# Ubuntu: sudo apt install clangd

AST Parsing Fails for Valid Code

If AST parsing fails for code that compiles correctly, it may be a Tree-sitter grammar limitation.

Solution:

  • Ensure the file has the correct extension for its language
  • Check for unusual syntax that may not be supported by the Tree-sitter grammar
  • Try using the file_search tool instead for text-based operations

Edit Operations Fail with "syntax error"

The edit engine validates syntax before and after edits.

Solution:

  • Ensure new_content is syntactically valid for the target language
  • Check that the selector matches exactly one node

Timeout Errors

Long-running operations may timeout.

Solution: Configure timeout values via environment variables:

export MCP_LSP_TIMEOUT="10m"      # LSP operations (default: 5m)
export MCP_SEARCH_TIMEOUT="2m"    # Search operations (default: 30s)

Permission Denied Errors

The server needs read/write access to workspace files.

Solution:

  • Ensure the user running the server has appropriate file permissions
  • Check that the workspace path is correct and accessible
  • On macOS, grant terminal/IDE full disk access if needed

Debug Logging

Enable debug logging to troubleshoot issues:

./bin/mcp-filepuff -workspace /path/to/workspace -log-level debug -log-file /tmp/mcp-filepuff.log

Verifying Installation

Use the ping tool to verify the server is running correctly:

{"tool": "ping"}

Expected response: "pong"

License

MIT License

S
Description
Mirror of github.com/lukaszraczylo/filepuff-mcp
Readme MIT 525 KiB
Languages
Go 97.4%
Shell 2.1%
Makefile 0.5%