MCP Personal

A collection of MCP servers for various personal productivity tools and utilities.

MCP Personal - Collection of Personal MCP Servers

A collection of Model Context Protocol (MCP) servers for various personal productivity tools and utilities.

Available MCP Servers

1. File Search Server (mcp_fd_server.py)

Fuzzy file NAME search capabilities using fd and fzf:

  • Fast file name search using fd (searches file names/paths, NOT contents)
  • Fuzzy filtering of file names with fzf for intelligent name matching
  • Pattern matching with regex and glob support for file names
  • Result limiting with limit parameter to restrict number of matches
  • Proper error handling for fzf exit codes (distinguishes "no matches" from errors)
  • Multiline mode (advanced): can also search file contents when enabled
  • Standalone CLI for testing and direct usage
  • Key point: Primary purpose is finding files by NAME, not searching contents

2. Fuzzy Search Server (mcp_fuzzy_search.py)

Advanced search with both file name and content capabilities using ripgrep and fzf:

  • File name fuzzy search - find files by partial/fuzzy names
  • Content search using ripgrep to search text within files
  • Fuzzy filtering of results using fzf --filter
  • Proper error handling for fzf exit codes (distinguishes "no matches" from errors)
  • Two distinct modes:
    • fuzzy_search_files: Search file NAMES/paths
    • fuzzy_search_content: Search file CONTENTS with path+content matching by default
  • PDF and document search (optional) - search through PDFs, Office docs, and archives using ripgrep-all
  • PDF page extraction (optional) - extract specific pages from PDFs using PyMuPDF with page label support
  • PDF information tools (optional) - get page labels, page count, and table of contents from PDF files:
    • get_pdf_page_labels: Get all page labels from a PDF file
    • get_pdf_page_count: Get the total number of pages in a PDF file
    • get_pdf_outline: Extract table of contents/bookmarks from a PDF file
  • Simplified interface - just provide fuzzy search terms (NO regex support)
  • Multiline record processing for complex pattern matching
  • Standalone CLI for testing and direct usage

3. SQLite Server (mcp_sqlite_server.py)

SQLite database operations with configurable read/write permissions:

  • Read-only by default - Write operations disabled unless explicitly enabled
  • Agent-friendly - Clear tool descriptions and examples for easy AI agent usage
  • In-memory database support - Use :memory: for temporary databases
  • Comprehensive operations - Query, execute, list tables, describe schema, create tables
  • Safety features - Query validation, write operation restrictions, clear error messages
  • Standalone CLI for testing and direct usage

Prerequisites

General Requirements

  • Python 3.10 or higher
  • uv (recommended) or pip

To install uv:

# macOS/Linux
curl -LsSf https://astral.sh/uv/install.sh | sh

# Or using pip (if you already have Python)
pip install uv

Note on Optional Features

The PDF search and extraction tools in the Fuzzy Search Server are optional. The server will work without these binaries installed - only the PDF-specific tools will be unavailable. This allows you to use the core fuzzy search functionality without requiring all dependencies.

File Search Server Requirements

The file search server requires the following command-line tools:

macOS

brew install fd fzf

Ubuntu/Debian

sudo apt install fd-find fzf
# Note: On Debian/Ubuntu, fd is installed as 'fdfind'

Other Systems

Fuzzy Search Server Requirements

The fuzzy search server requires:

macOS

brew install ripgrep fzf

# For PDF search capabilities (optional)
brew install ripgrep-all pandoc
pip install PyMuPDF  # Or: uv pip install PyMuPDF

Ubuntu/Debian

sudo apt install ripgrep fzf

# For PDF search capabilities (optional)
# Install ripgrep-all
cargo install ripgrep-all  # Requires Rust/cargo

# Install PyMuPDF
pip install PyMuPDF  # Or: uv pip install PyMuPDF

# Install pandoc
sudo apt install pandoc

Other Systems

Installation

Clone the Repository

git clone https://github.com/yourusername/mcp-personal.git
cd mcp-personal

Configure MCP Servers

Using Claude Code CLI

The easiest way to add MCP servers to Claude Code is using the CLI:

# Add published npm servers (recommended to use -s user for global access)
claude mcp add sequential-thinking -s user -- npx -y @modelcontextprotocol/server-sequential-thinking

# Add custom Python servers from this repository
# IMPORTANT: Use -s user for personal tools you want available across all projects
# Without -s flag, servers are only available in current directory and are temporary

# Easy method: Use $(pwd) when in the project directory
cd /path/to/mcp-personal
claude mcp add file-search -s user -- $(pwd)/mcp_fd_server.py
claude mcp add fuzzy-search -s user -- $(pwd)/mcp_fuzzy_search.py
claude mcp add sqlite -s user -- $(pwd)/mcp_sqlite_server.py

# Or use relative paths (also from project directory)
claude mcp add file-search -s user -- ./mcp_fd_server.py
claude mcp add fuzzy-search -s user -- ./mcp_fuzzy_search.py
claude mcp add sqlite -s user -- ./mcp_sqlite_server.py

# Using absolute paths (works from anywhere)
claude mcp add file-search -s user -- /path/to/mcp-personal/mcp_fd_server.py
claude mcp add fuzzy-search -s user -- /path/to/mcp-personal/mcp_fuzzy_search.py
claude mcp add sqlite -s user -- /path/to/mcp-personal/mcp_sqlite_server.py

# Add SQLite server with write permissions enabled
claude mcp add sqlite -s user -- /path/to/mcp-personal/mcp_sqlite_server.py --allow-writes

# Or using environment variable
claude mcp add sqlite -s user -e MCP_SQLITE_ALLOW_WRITES=true -- /path/to/mcp-personal/mcp_sqlite_server.py

# Add Python servers with Python interpreter explicitly
claude mcp add my-server -s user -- python /path/to/my_mcp_server.py

# Add servers with arguments
claude mcp add my-server -s user -- python /path/to/server.py arg1 arg2

# Add servers with environment variables
claude mcp add my-server -s user -e API_KEY=your_key -e DEBUG=true -- python /path/to/server.py

# Scope options:
# -s local (default): Temporary, only in current directory
# -s project: Shared with team via .mcp.json file
# -s user: Personal, available across all your projects (recommended)

Note:

  • The -- separator is important before the command and its arguments
  • Environment variables use -e KEY=value syntax
  • Use -s user for personal servers available across all projects
  • Both relative and absolute paths work

Manual Configuration (Claude Desktop)

For Claude Desktop, manually add servers to ~/Library/Application Support/Claude/claude_desktop_config.json:

{
  "mcpServers": {
    "file-search": {
      "command": "/path/to/mcp-personal/mcp_fd_server.py"
    },
    "fuzzy-search": {
      "command": "/path/to/mcp-personal/mcp_fuzzy_search.py"
    },
    "sqlite": {
      "command": "/path/to/mcp-personal/mcp_sqlite_server.py",
      "args": ["--allow-writes"],
      "env": {
        "MCP_SQLITE_ALLOW_WRITES": "true"
      }
    }
  }
}

Make Scripts Executable

# Make all Python scripts executable
chmod +x *.py

For Development

# Install with development dependencies
uv sync --dev

# Or use make
make setup

Testing and Development

MCP Inspector

The MCP Inspector is an interactive developer tool for testing and debugging MCP servers. It provides a web-based interface that allows you to:

  • Visually test your MCP servers with an interactive UI
  • Debug server implementations by examining request/response flows
  • Test tools, resources, and prompts with different arguments
  • Validate server behavior before deployment

Quick Testing

Test any MCP server using the inspector:

# Test the file search server
npx @modelcontextprotocol/inspector ./mcp_fd_server.py

# Test the fuzzy search server  
npx @modelcontextprotocol/inspector ./mcp_fuzzy_search.py

# Test the SQLite server (read-only mode)
npx @modelcontextprotocol/inspector ./mcp_sqlite_server.py

# Test the SQLite server with write permissions
npx @modelcontextprotocol/inspector ./mcp_sqlite_server.py -- --allow-writes

This will:

  1. Start the MCP Inspector proxy server (default port 6277)
  2. Launch a web interface (default port 6274)
  3. Connect to your MCP server via stdio transport
  4. Open your browser to the inspector interface

Using the Inspector

Once the inspector is running:

  1. Navigate to the web interface (usually http://localhost:6274)
  2. Explore the tabs:
    • Tools: Test search_files, filter_files, fuzzy_search_files, fuzzy_search_content, fuzzy_search_documents, extract_pdf_pages
    • Resources: View any exposed resources (if implemented)
    • Prompts: Test any exposed prompts (if implemented)
  3. Test different scenarios:
    • Try various search patterns and filters
    • Test multiline functionality
    • Experiment with different file paths and flags
    • Test PDF search with fuzzy_search_documents (if binaries installed)
    • Test PDF page extraction with extract_pdf_pages (if binaries installed)
    • Validate error handling with invalid inputs

Advanced Configuration

You can also use configuration files for complex setups:

# Using a config file
npx @modelcontextprotocol/inspector --config config.json

# Passing environment variables
npx @modelcontextprotocol/inspector -e "DEBUG=1" ./mcp_fuzzy_search.py

# Custom ports
npx @modelcontextprotocol/inspector --mcpp-port 3001 --mcpi-port 3002 ./mcp_fd_server.py

The MCP Inspector is particularly valuable for:

  • Rapid prototyping - quickly test new functionality
  • Debugging - identify issues before integration with Claude
  • Documentation - understand exactly what your server exposes
  • Validation - ensure proper error handling and edge cases

Usage

File Search Server

As an MCP Server

Once configured in Claude Desktop, you can use natural language to search for files by NAME:

  • "Find all Python files in the src directory" (searches file names ending in .py)
  • "Search for files with 'config' in their name" (fuzzy matches file names)
  • "Find test files by name" (searches for files with 'test' in the name)
  • "Use fuzzy search to find 'mainpy'" (finds main.py, main_py.txt, etc.)

CLI Usage

The file search server also works as a standalone CLI tool:

# Search for files by name pattern
./mcp_fd_server.py search "\.py$" /path/to/search  # Find Python files by name
./mcp_fd_server.py search "\.py$" . --limit 10  # Limit to first 10 results

# Search with additional fd flags
./mcp_fd_server.py search "\.js$" . --flags "--hidden --no-ignore"

# Fuzzy filter file names/paths
./mcp_fd_server.py filter "main" "\.py$" /path/to/search  # Fuzzy search for 'main' in Python file names
./mcp_fd_server.py filter "test" "" . --limit 20  # Find up to 20 test-related files

# Get the best fuzzy match by name
./mcp_fd_server.py filter "app" "" . --first  # Find file with name most similar to 'app'

# Multiline mode - search file CONTENTS (not just names)
./mcp_fd_server.py filter "class function" "" src --multiline  # Find files containing both terms
./mcp_fd_server.py filter "TODO" "" . --multiline --limit 5  # Find first 5 files with TODOs

Fuzzy Search Server

As an MCP Server

Once configured in Claude Desktop, you can use natural language for advanced searching:

  • "Search for TODO comments that mention 'implement'"
  • "Find all files with 'test' in the name using fuzzy search"
  • "Look for error handling code in Python files"
  • "Search for configuration files containing database settings"
  • "Find method definitions named 'update_ondemand_max_spend'"
  • "Search for async functions with error handling"
  • "Search for 'update' in test.py files only" (works because default mode matches paths too!)
  • "Search for 'async' in content only, ignore file paths" (use content_only mode)
  • "Search for 'vector' in PDF documents" (requires ripgrep-all)
  • "Find all references to 'machine learning' in PDFs and Word documents"
  • "Extract pages 5-10 from the user manual PDF"
  • "Get the table of contents from the research paper PDF"
  • "Show me the outline of chapters in the user manual"

CLI Usage

The fuzzy search server also works as a standalone CLI tool:

# Fuzzy search for file NAMES/PATHS
./mcp_fuzzy_search.py search-files "main" /path/to/search  # Find files with 'main' in the name
./mcp_fuzzy_search.py search-files "test" . --hidden --limit 10  # Find test files by name
./mcp_fuzzy_search.py search-files "config" / --confirm-root  # Search from root (requires explicit confirmation)

# Search file CONTENTS and filter with fzf (NO regex support)
# Default: Matches on BOTH file paths AND content
# Works with both directories and individual files
./mcp_fuzzy_search.py search-content "TODO implement" .  # Find lines containing both terms
./mcp_fuzzy_search.py search-content "test.py: update" .  # Find 'update' in test.py files
./mcp_fuzzy_search.py search-content "function" specific_file.py  # Search within a single file
./mcp_fuzzy_search.py search-content "error handle" src --rg-flags "-i"  # Case insensitive
./mcp_fuzzy_search.py search-content "config" / --confirm-root  # Search from root (requires explicit confirmation)

# Content-only mode: Match ONLY on content, ignore file paths
./mcp_fuzzy_search.py search-content "TODO implement" . --content-only  # Pure content search
./mcp_fuzzy_search.py search-content "async await" src --content-only  # Won't match file paths

# Multiline mode - changes behavior:
# search-files --multiline: Searches file CONTENTS instead of names
./mcp_fuzzy_search.py search-files "class constructor" src --multiline  # Find files CONTAINING these terms

# search-content --multiline: Treats whole files as searchable units
./mcp_fuzzy_search.py search-content "async await" . --multiline  # Find files with both terms anywhere
./mcp_fuzzy_search.py search-content "try catch" . --multiline --content-only  # Content-only + multiline

# PDF and document search (requires optional binaries)
./mcp_fuzzy_search.py search-documents "machine learning" .  # Search PDFs and docs
./mcp_fuzzy_search.py search-documents "invoice total" invoices/ --file-types "pdf"  # PDFs only
./mcp_fuzzy_search.py search-documents "contract" . --file-types "pdf,docx" --limit 5
./mcp_fuzzy_search.py search-documents "report" / --confirm-root  # Search from root (requires explicit confirmation)

# Extract specific pages from PDFs (using PyMuPDF)
./mcp_fuzzy_search.py extract-pdf manual.pdf "1,3,5-7"  # Extract pages 1, 3, 5, 6, 7
./mcp_fuzzy_search.py extract-pdf report.pdf "v-vii,1,ToC"  # Use page labels
./mcp_fuzzy_search.py extract-pdf report.pdf "10-20" --format html  # Extract as HTML
./mcp_fuzzy_search.py extract-pdf thesis.pdf "100-105" --preserve-layout  # Keep layout
./mcp_fuzzy_search.py extract-pdf book.pdf "1-50" --fuzzy-hint "neural network"  # Filter by content
./mcp_fuzzy_search.py extract-pdf book.pdf "0,266-273" --zero-based  # 0-based indices (pages 1, 267-274)
./mcp_fuzzy_search.py extract-pdf book.pdf "1-50" --one-based  # 1-based indices (pages 1-50)

# Get PDF information
./mcp_fuzzy_search.py page-labels manual.pdf  # List all page labels
./mcp_fuzzy_search.py page-labels manual.pdf --start 100 --limit 20  # Get labels for pages 100-119
./mcp_fuzzy_search.py page-count manual.pdf  # Get total page count
./mcp_fuzzy_search.py pdf-outline manual.pdf  # Get table of contents
./mcp_fuzzy_search.py pdf-outline manual.pdf --max-depth 2  # Limit to 2 levels
./mcp_fuzzy_search.py pdf-outline manual.pdf --fuzzy-filter "chapter"  # Filter by title
./mcp_fuzzy_search.py pdf-outline manual.pdf --no-simple  # Detailed output with links

SQLite Server

As an MCP Server

Once configured in Claude Desktop, you can use natural language for database operations:

  • "List all tables in the database"
  • "Show me the schema for the users table"
  • "Query the last 10 orders from the orders table"
  • "Count active users in the database"
  • "Update user status to inactive for users who haven't logged in for a year" (requires write permissions)
  • "Create a new table for storing session data" (requires write permissions)

CLI Usage

The SQLite server also works as a standalone CLI tool:

# Query database (read-only operations)
./mcp_sqlite_server.py query "SELECT * FROM users" database.db
./mcp_sqlite_server.py query "SELECT COUNT(*) as total FROM orders WHERE status = 'active'" sales.db

# List all tables
./mcp_sqlite_server.py list-tables database.db

# Describe table schema
./mcp_sqlite_server.py describe-table users database.db

# Execute write operations (requires --allow-writes flag)
./mcp_sqlite_server.py execute "INSERT INTO users (name, email) VALUES ('John', 'john@example.com')" database.db --allow-writes
./mcp_sqlite_server.py execute "UPDATE users SET active = 0 WHERE last_login < date('now', '-1 year')" database.db --allow-writes

# Use in-memory database for testing
./mcp_sqlite_server.py query "SELECT sqlite_version()" :memory:

Multiline Search Mode

Both MCP servers support multiline search mode which changes the search behavior:

What is Multiline Mode?

Default behavior (multiline=false):

  • File Search Server: Searches file NAMES/PATHS only
  • Fuzzy Search Server: Searches line-by-line within file contents

With multiline mode (multiline=true):

  • File Search Server: Switches to searching file CONTENTS instead of names
  • Fuzzy Search Server: Treats entire file contents as single searchable units

When to Use Multiline Mode

Multiline mode is for searching file CONTENTS (not names):

  • Finding class definitions with their methods: "class UserService authenticate" (fuzzy match in contents)
  • Locating function implementations: "async function await fetch" (all terms in one file)
  • Searching for configuration blocks: "database host port" (finds files containing all terms)
  • Finding code structures across lines: "try catch finally" (fuzzy matches across lines)
  • Important: This searches CONTENTS, not file names!

Multiline Examples

File Search Server Multiline (Content Search)

# With --multiline, searches file CONTENTS instead of names
# Find files CONTAINING these terms (not in file names)
./mcp_fd_server.py filter "class constructor method" "" src --multiline

# Find Python files CONTAINING specific patterns  
./mcp_fd_server.py filter "class def return" "" . --multiline

# Find files CONTAINING database configuration
./mcp_fd_server.py filter "database host password" "" config --multiline

Fuzzy Search Server Multiline

# search-files with --multiline searches file CONTENTS (not names)
./mcp_fuzzy_search.py search-files "async function await" src --multiline

# search-content with --multiline treats files as single units
./mcp_fuzzy_search.py search-content "try catch finally" . --multiline

# Find files CONTAINING class definitions with specific methods
./mcp_fuzzy_search.py search-content "class constructor render" src --multiline

Performance Considerations

  • File size: Multiline mode reads entire files into memory; best for typical source code files
  • Result size: Multiline results include complete file contents, which may be truncated for display
  • Pattern complexity: Simple fuzzy patterns work well; complex queries may be slower

Tips for Multiline Queries

  1. Use specific terms: "class MyClass def method" is better than just "class def" (no regex!)
  2. Combine structure and content: "import React export default" finds React components
  3. Mind the output: Results show the entire matching file content
  4. Test incrementally: Start with simple patterns and refine

fzf Search Syntax Guide

Both MCP servers use fzf's extended search syntax for powerful fuzzy filtering. Understanding this syntax will help you construct precise queries.

IMPORTANT: The fuzzy_filter parameter in fuzzy_search_content does NOT support regular expressions. It uses fzf's fuzzy matching syntax as described below. If you need regex-like patterns, use the position anchors and exact matching features of fzf syntax instead.

Basic Syntax

PatternDescriptionExample
termFuzzy match (default)config matches "configuration"
term1 term2AND logic (all terms must match)main config requires both terms
term1 | term2OR logic (any term can match)py$ | js$ | go$ matches files ending in any

Exact Matching

PatternDescriptionExample
'termPartial exact match'main exactly matches "main" substring
'term'Exact boundary match'main.py' matches exactly at word boundaries

Position Anchors

PatternDescriptionExample
^termPrefix match (starts with)^src matches "src/file.py"
term$Suffix match (ends with).json$ matches "config.json"
^term$Exact match (entire string)^README$ matches only "README"

Negation (Exclusion)

PatternDescriptionExample
!termExclude fuzzy matchesconfig !test excludes test files
!'termExclude exact matches!'backup' excludes files with exact "backup"
!^termExclude prefix matches!^. excludes hidden files
!term$Exclude suffix matches!.tmp$ excludes temporary files

Advanced Examples

Note: These examples show how to achieve regex-like filtering WITHOUT using regular expressions, since fuzzy_filter does not support regex.

# Find Python configuration files, excluding tests
config .py$ !test

# Find main files in src directory with multiple extensions  
^src/ main py$ | js$ | go$

# Find exact package manager files
'package.json' | 'yarn.lock' | 'Pipfile'

# Find TODO comments in code files, excluding documentation
TODO .py$ | .js$ | .go$ !README !docs/

# Find function definitions, excluding test files
'def ' .py$ !test !spec

# Find configuration files with specific extensions, excluding backups
config .json$ | .yaml$ | .toml$ !.bak$ !.old$

Content Search Specific Patterns

When using fuzzy_search_content, queries work on the format file:line:content:

Default Mode (matches file paths AND content):

# Find implementation TODOs in specific file types
TODO implement .py: | .js:  # Matches TODO in .py or .js files

# Find error handling in specific files
error 'main.py:' | 'app.js:'  # Matches 'error' in main.py or app.js

# Find updates in test files
test.py: update  # Matches 'update' in files named test.py

# Find async functions with error handling
'async def' error .py$  # Matches in Python files

Content-Only Mode (ignores file paths):

# With --content-only flag or content_only=true parameter
# These will ONLY match the content, not file names:

# Find TODO comments regardless of filename
TODO implement  # Won't match files named 'TODO.txt'

# Find async/await patterns
async await catch  # Pure content search

# Find class definitions
'class ' 'def __init__'  # Won't match 'class.py' filename

ripgrep (rg) Flags Reference

The fuzzy_search_content tool accepts rg_flags for enhanced searching. Here are the most useful flags:

Case Sensitivity

FlagDescriptionExample
-i, --ignore-caseCase insensitive searchrg -i "todo" matches TODO, Todo, todo
-S, --smart-caseCase insensitive if lowercase, sensitive if mixedrg -S "Todo" is case sensitive
-s, --case-sensitiveForce case sensitive (default)rg -s "TODO" matches only TODO

File Type Filtering

FlagDescriptionExample
-t TYPEOnly search specific file types-t py searches Python files only
-T TYPEExclude specific file types-T test excludes test files
--type-listShow all supported file typesrg --type-list

Context Lines

FlagDescriptionExample
-A NUMShow NUM lines after match-A 3 shows 3 lines after
-B NUMShow NUM lines before match-B 2 shows 2 lines before
-C NUMShow NUM lines before and after-C 3 shows 3 lines both sides

File Handling

FlagDescriptionExample
--hiddenSearch hidden files/directories--hidden includes .hidden files
--no-ignoreIgnore .gitignore rules--no-ignore searches ignored files
-uReduce filtering (1-3 times)-uu = --no-ignore --hidden

Pattern Matching

FlagDescriptionExample
-FLiteral string search (no regex)-F searches for exact text
-wMatch whole words only-w won't match partial words
-vInvert match (show non-matches)-v shows lines without matches
-xMatch entire lines only-x matches exact line

Advanced Features

FlagDescriptionExample
-UEnable multiline matching-U (note: use multiline parameter instead)
-PUse PCRE2 regex engine-P for advanced regex features
-oShow only matching parts-o shows just matching text

Output Control

FlagDescriptionExample
-cCount matches per file-c shows count only
-lShow only filenames with matches-l lists files with matches
--columnShow column numbers--column includes column info

Practical Combinations

# Case-insensitive search with context in Python files
rg_flags: "-i -C 3 -t py"

# Search all files including hidden and ignored, with context
rg_flags: "-uu -C 2"

# Find exact function signatures in code files
rg_flags: "-F -w -t py -t js -t go"

# Search for TODOs with file types, case insensitive, show context
rg_flags: "-i -C 1 -t py -t js --no-ignore"

# Multi-line class definitions with context
rg_flags: "-U -C 3 -t py"

# Literal string search in all text files
rg_flags: "-F --no-ignore -t txt -t md -t rst"

MCP Tools Documentation

File Search Server Tools

search_files

Find files by NAME using fd with regex or glob patterns.

Purpose: Search for files when you know exact patterns, extensions, or regex for file NAMES.

Parameters:

  • pattern (required): Regex or glob pattern to match file names
  • path (optional): Directory to search in (defaults to current directory)
  • limit (optional): Maximum number of results to return (default: 0 = no limit)
  • flags (optional): Additional flags to pass to fd

Example:

{
  "pattern": r"\.py$",  # Find files with names ending in .py
  "path": "/home/user/projects",
  "flags": "--hidden --no-ignore"
}

filter_files

Fuzzy search for files by NAME using fzf's fuzzy matching.

Purpose: Find files when you only know partial or approximate file NAMES.

Parameters:

  • filter (required): Fuzzy search string to match against file names/paths
  • pattern (optional): Initial pattern for fd to pre-filter
  • path (optional): Directory to search in
  • first (optional): Return only the best match
  • limit (optional): Maximum number of results to return (default: 0 = no limit)
  • fd_flags (optional): Extra flags for fd
  • fzf_flags (optional): Extra flags for fzf
  • multiline (optional): When true, searches file CONTENTS instead of names (default: false)

Note: When both first and limit are provided, first takes precedence and returns only the best match.

Example (File Name Search):

{
  "filter": "test",  # Fuzzy match 'test' in file names
  "pattern": r"\.py$",  # Only Python files
  "path": "./src",
  "first": true
}

Multiline Example (Content Search):

{
  "filter": "class function return",  # Find files containing all these terms
  "pattern": "",
  "path": "./src",
  "multiline": true  # Search CONTENTS, not names
}

Fuzzy Search Server Tools

fuzzy_search_files

Search for file NAMES/PATHS using fuzzy matching.

Purpose: Find files by NAME when you only know partial names (e.g., "mainpy" finds "main.py").

Parameters:

  • fuzzy_filter (required): Fuzzy search string for file names/paths
  • path (optional): Directory to search in (defaults to current directory)
  • hidden (optional): Include hidden files (default: false)
  • limit (optional): Maximum results to return (default: 20)
  • multiline (optional): When true, searches file CONTENTS instead of names (default: false)
  • confirm_root (optional): Allow searching from root directory (/) (default: false)

Example (File Name Search):

{
  "fuzzy_filter": "main",  # Finds main.py, main.js, domain.py, etc.
  "path": "/home/user/projects",
  "hidden": true,
  "limit": 10
}

Multiline Example (Content Search):

{
  "fuzzy_filter": "import export",  # Find files containing both terms
  "path": "./src",
  "multiline": true,  # Search CONTENTS, not names
  "limit": 5
}

fuzzy_search_content

Search file contents with fuzzy filtering, matching on BOTH file paths AND content by default.

Purpose: Find specific text/code using fuzzy search that considers both where it is (path) and what it is (content). Works consistently with both directories and individual files.

Parameters:

  • fuzzy_filter (required): Fuzzy search query for filtering (does NOT support regex - use fzf syntax)
  • path (optional): Directory/file to search in (defaults to current directory)
    • Enhanced file path support: Can now search both directories and individual files
    • Automatically includes filename in output when searching a single file for consistent results
  • hidden (optional): Search hidden files (default: false)
  • limit (optional): Maximum results to return (default: 20)
  • rg_flags (optional): Extra flags for ripgrep (see ripgrep flags reference)
  • multiline (optional): Enable multiline record processing (default: false)
  • content_only (optional): Match ONLY on content, ignore file paths (default: false)
  • confirm_root (optional): Allow searching from root directory (/) (default: false)

Matching Behavior:

  • Default (content_only=false): Matches on BOTH file paths AND content (skips line numbers)
    • This is why "test.py: update" finds "update" in test.py files - it matches the path!
    • Searching "src TODO" finds TODO comments in files under src/ directory
    • Even just "update" will match files named "update.py" OR containing "update"
  • With content_only=true: Matches ONLY on content, ignoring file paths entirely
    • Pure content search - "update" won't match "update.py" filename, only content

Example (Default - Path + Content):

{
  "fuzzy_filter": "test.py: TODO implement",  # Find TODOs in test.py files
  "path": "./src",
  "rg_flags": "-i",
  "limit": 15
}

Example (Single File Search):

{
  "fuzzy_filter": "function async",  # Find async functions in a specific file
  "path": "./src/main.py",  # Search within a single file
  "limit": 10
}

Example (Content Only):

{
  "fuzzy_filter": "async await catch",  # Find these terms in content only
  "path": "./src",
  "content_only": true,  # Ignore file paths in matching
  "limit": 10
}

fuzzy_search_documents

Search through PDFs and other document formats using ripgrep-all (requires optional binaries).

Purpose: Search PDFs, Office documents, archives, and other binary formats that regular text search can't handle.

Parameters:

  • fuzzy_filter (required): Fuzzy search query for document content
  • path (optional): Directory/file to search in (defaults to current directory)
  • file_types (optional): Comma-separated file types to search (e.g., "pdf,docx,epub")
  • preview (optional): Include preview context (default: true)
  • limit (optional): Maximum results to return (default: 20)
  • confirm_root (optional): Allow searching from root directory (/) (default: false)

Example:

{
  "fuzzy_filter": "machine learning algorithm",
  "path": "./research",
  "file_types": "pdf,epub",
  "limit": 10
}

Returns:

{
  "matches": [
    {
      "file": "/path/to/document.pdf",
      "line": 0,
      "content": "topology.",  # Content without "Page N: " prefix
      "match_text": "topology",
      "page": 542,  # 1-based page number (from ripgrep-all)
      "page_index_0based": 541,  # 0-based page index for programmatic access
      "page_label": "19"  # Actual PDF page label (only for PDFs with PyMuPDF)
    }
  ]
}

Note: For PDF files, the tool returns:

  • page: The 1-based page number from ripgrep-all (e.g., 542 means the 542nd page)
  • page_index_0based: The 0-based page index for programmatic access (e.g., 541 for page 542)
  • page_label: The actual page label as shown in PDF readers (e.g., "vii", "ToC", "19")

The content field no longer includes the "Page N: " prefix for cleaner output.

extract_pdf_pages

Extract specific pages from a PDF and convert to various formats using PyMuPDF.

Purpose: Extract individual pages or page ranges from PDFs with support for page labels/aliases as they appear in PDF readers.

Parameters:

  • file (required): Path to PDF file
  • pages (required): Comma-separated page specifications - supports:
    • Page labels: "v", "vii", "ToC", "Introduction" (as shown in PDF readers)
    • Page ranges: "v-vii", "1-5"
    • Physical pages: "1", "14" (1-based if not found as label)
    • Mixed: "v,vii,1,5-8,ToC"
  • format (optional): Output format - markdown, html, plain (default: markdown)
  • preserve_layout (optional): Try to preserve original layout (default: false)
  • clean_html (optional): Strip HTML styling tags like <span style="..."> (default: true)
  • fuzzy_hint (optional): Fuzzy search string to filter extracted pages by content
  • zero_based (optional): Interpret page numbers as 0-based indices (default: false)
    • When true, all numbers are treated as direct 0-based page indices
    • "0" = first page, "266" = 267th page, "0-4" = first 5 pages
    • No page label lookup is performed when this is true
    • Cannot be used together with one_based
  • one_based (optional): Interpret page numbers as 1-based indices (default: false)
    • When true, all numbers are treated as direct 1-based page indices
    • "1" = first page, "267" = 267th page, "1-5" = first 5 pages
    • No page label lookup is performed when this is true
    • Cannot be used together with zero_based

Example:

{
  "file": "research_paper.pdf",
  "pages": "v-vii,1,5-10,ToC",  # Mix of page labels and numbers
  "format": "markdown",
  "clean_html": true,
  "fuzzy_hint": "neural network"  # Only include pages mentioning this
}

# Example with zero_based=true
{
  "file": "research_paper.pdf",
  "pages": "0,266-273",  # Direct 0-based indices: page 1 and pages 267-274
  "zero_based": true
}

# Example with one_based=true
{
  "file": "research_paper.pdf",
  "pages": "1,267-274",  # Direct 1-based indices: pages 1, 267-274
  "one_based": true
}

get_pdf_page_labels

Get all page labels from a PDF file.

Purpose: Returns a mapping of page indices to their labels/aliases as shown in PDF readers, helpful for understanding available page labels before extraction.

Parameters:

  • file (required): Path to PDF file
  • start (optional): 0-based start index for slicing results (default: 0)
  • limit (optional): Maximum number of labels to return (default: all pages)

Example:

{
  "file": "research_paper.pdf"
}

# Returns something like:
{
  "page_labels": {
    "0": "Cover",
    "1": "i",
    "2": "ii", 
    "3": "iii",
    "4": "iv",
    "5": "v",
    "6": "vi",
    "7": "vii",
    "8": "viii",
    "9": "1",
    "10": "2",
    "11": "3"
  },
  "page_count": 150
}

# Example with slicing:
{
  "file": "research_paper.pdf",
  "start": 100,
  "limit": 20
}

# Returns subset like:
{
  "page_labels": {
    "100": "87",
    "101": "88",
    "102": "89",
    "103": "90",
    "104": "91"
    # ... up to 20 entries
  },
  "page_count": 150
}

get_pdf_page_count

Get the total number of pages in a PDF file.

Purpose: Returns the total page count, useful for understanding the document size before extraction.

Parameters:

  • file (required): Path to PDF file

Example:

{
  "file": "research_paper.pdf"
}

# Returns:
{
  "page_count": 150
}

get_pdf_outline

Extract the table of contents (outline/bookmarks) from a PDF file.

Purpose: Returns the hierarchical outline structure with levels, titles, page numbers, and page labels, helpful for navigating complex PDFs and understanding document structure.

Parameters:

  • file (required): Path to PDF file
  • simple (optional): Return basic info (default: true) or detailed info with link data (false)
  • max_depth (optional): Maximum depth to traverse in the outline hierarchy (default: unlimited)
  • fuzzy_filter (optional): Fuzzy search string to filter outline entries by title using fzf

Example:

{
  "file": "research_paper.pdf"
}

# Returns (simple mode):
{
  "outline": [
    [1, "Introduction", 1, "i"],
    [1, "Chapter 1: Background", 5, "1"],
    [2, "1.1 History", 6, "2"],
    [2, "1.2 Related Work", 10, "6"],
    [1, "Chapter 2: Methods", 15, "11"],
    [2, "2.1 Data Collection", 16, "12"],
    [3, "2.1.1 Sources", 17, "13"],
    [2, "2.2 Analysis", 20, "16"]
  ],
  "total_entries": 8,
  "max_depth_found": 3
}

# Example with filtering:
{
  "file": "research_paper.pdf",
  "fuzzy_filter": "chapter"
}

# Returns:
{
  "outline": [
    [1, "Chapter 1: Background", 5, "1"],
    [1, "Chapter 2: Methods", 15, "11"]
  ],
  "total_entries": 8,
  "max_depth_found": 3,
  "filtered_count": 2
}

# Example with detailed output:
{
  "file": "research_paper.pdf",
  "simple": false,
  "max_depth": 2
}

# Returns:
{
  "outline": [
    [1, "Introduction", 1, "i", {
      "page": 1,
      "uri": "#page=1&zoom=100,0,0",
      "is_external": false,
      "is_open": true,
      "dest": {
        "kind": 1,
        "page": 0,
        "uri": "#page=1&zoom=100,0,0"
      }
    }],
    # ... more entries with link details
  ],
  "total_entries": 8,
  "max_depth_found": 2
}

Outline Format:

  • Simple mode returns: [level, title, page, page_label]
    • level: Hierarchy level (1-based, 1 = top level)
    • title: The bookmark/outline entry title
    • page: Page number (1-based)
    • page_label: Page label as shown in PDF readers (e.g., "i", "ii", "1", "ToC")
  • Detailed mode adds a 5th element with link information including destination details

SQLite Server Tools

query

Execute SELECT queries on the database.

Parameters:

  • query (required): SELECT query to execute
  • db_path (optional): Path to SQLite database (defaults to configured db_path or ':memory:')

Example:

{
  "query": "SELECT * FROM users WHERE active = 1 ORDER BY created_at DESC LIMIT 10",
  "db_path": "myapp.db"
}

execute

Execute INSERT, UPDATE, or DELETE queries (requires write permissions).

Parameters:

  • query (required): INSERT, UPDATE, or DELETE query to execute
  • db_path (optional): Path to SQLite database

Example:

{
  "query": "UPDATE users SET last_login = datetime('now') WHERE id = 123",
  "db_path": "myapp.db"
}

list_tables

List all tables in the database.

Parameters:

  • db_path (optional): Path to SQLite database

Example:

{
  "db_path": "myapp.db"
}

describe_table

Get detailed schema information for a specific table, including columns, types, constraints, and indexes.

Parameters:

  • table_name (required): Name of the table to describe
  • db_path (optional): Path to SQLite database

Example:

{
  "table_name": "users",
  "db_path": "myapp.db"
}

create_table

Create a new table with specified columns (requires write permissions).

Parameters:

  • table_name (required): Name of the table to create
  • columns (required): List of column definitions
  • db_path (optional): Path to SQLite database

Column Definition:

  • name (required): Column name
  • type (required): SQLite data type (TEXT, INTEGER, REAL, BLOB, etc.)
  • constraints (optional): Column constraints (PRIMARY KEY, NOT NULL, UNIQUE, etc.)

Example:

{
  "table_name": "sessions",
  "columns": [
    {
      "name": "id",
      "type": "TEXT",
      "constraints": "PRIMARY KEY"
    },
    {
      "name": "user_id",
      "type": "INTEGER",
      "constraints": "NOT NULL"
    },
    {
      "name": "created_at",
      "type": "TIMESTAMP",
      "constraints": "DEFAULT CURRENT_TIMESTAMP"
    },
    {
      "name": "expires_at",
      "type": "TIMESTAMP",
      "constraints": "NOT NULL"
    }
  ],
  "db_path": "myapp.db"
}

Development

Project Structure

mcp-personal/
├── mcp_fd_server.py      # File search MCP server
├── mcp_fuzzy_search.py   # Fuzzy content search MCP server
├── mcp_sqlite_server.py  # SQLite database MCP server
├── tests/                # Test suite
│   ├── test_simple.py    # Direct function tests
│   ├── test_fd_server.py # File search MCP integration tests
│   ├── test_fuzzy_search.py # Fuzzy search tests
│   ├── test_sqlite_server.py # SQLite server tests
│   └── test_cli.py       # CLI interface tests
├── pyproject.toml        # Project configuration
├── Makefile              # Development commands
├── CLAUDE.md             # Claude-specific instructions
└── README.md             # This file

Adding New MCP Servers

To add a new MCP server to this collection:

  1. Create a new Python file (e.g., mcp_new_server.py)
  2. Implement using FastMCP framework
  3. Add tests in the tests/ directory
  4. Update this README with documentation
  5. Add configuration example for Claude Desktop

Running Tests

# Run all tests
make test

# Run specific test categories
make test-simple  # Direct function tests
make test-cli     # CLI interface tests
make test-full    # Full MCP integration tests

# Run with coverage
make test-cov

Development Commands

make help         # Show all available commands
make setup        # Install development dependencies
make test         # Run tests
make lint         # Run linting
make format       # Format code
make type-check   # Run type checking
make clean        # Clean generated files

Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Make your changes
  4. Run tests (make test)
  5. Run linting (make check)
  6. Commit your changes
  7. Push to the branch (git push origin feature/amazing-feature)
  8. Open a Pull Request

Architecture

All MCP servers in this collection are built using:

  • FastMCP: High-level MCP server framework from the official Python SDK
  • uv: Fast Python package manager
  • Self-contained scripts: Each server uses #!/usr/bin/env -S uv run --script for easy deployment

File Search Server

Additionally uses:

  • fd: Modern file finder written in Rust
  • fzf: Command-line fuzzy finder

Fuzzy Search Server

Additionally uses:

  • ripgrep: Extremely fast search tool that respects gitignore
  • fzf: Command-line fuzzy finder (used in filter mode)

Security Considerations

General

  • All servers run with the permissions of the user executing them
  • Consider the security implications of each server's capabilities
  • Review server code before installation

Root Path Protection

  • Built-in safety mechanism: All search functions prevent accidental searches from root directory (/) by default
  • Searching from root without explicit confirmation returns an error message
  • To search from root directory, you must explicitly set confirm_root=True (MCP tools) or use --confirm-root flag (CLI)
  • This prevents unintended performance issues and excessive filesystem access
  • Cross-platform support: protects against both Unix root (/) and Windows drive roots (C:, etc.)

File Search Server

  • Has filesystem access based on user permissions
  • Be cautious when searching in sensitive directories
  • The --no-ignore flag will include files normally hidden by .gitignore

Fuzzy Search Server

  • Has filesystem read access based on user permissions
  • Can search file contents, including source code and configuration files
  • Respects .gitignore by default (use --hidden to include ignored files)
  • Be mindful when searching in repositories with sensitive data

SQLite Server

  • Read-only by default - Prevents accidental data modification
  • Write operations require explicit --allow-writes flag or environment variable
  • Has full database access based on file permissions
  • Can execute arbitrary SQL queries when write mode is enabled
  • Be extremely cautious with write permissions on production databases
  • Consider using separate read-only database users when possible

Troubleshooting

"Cannot find the fd binary"

  • Ensure fd is installed and in your PATH
  • On Debian/Ubuntu, fd might be installed as fdfind

"Cannot find the fzf binary"

  • Install fzf using your package manager
  • Ensure it's available in your PATH

"Searching from root directory (/) is likely incorrect and could be very slow"

  • This safety message appears when trying to search from the root directory without explicit confirmation
  • To search from root, add confirm_root=True parameter (MCP tools) or --confirm-root flag (CLI)
  • Consider using a more specific directory path instead for better performance
  • Example: ./mcp_fuzzy_search.py search-files "config" / --confirm-root

Tests failing

  • Check that required binaries are installed for each server
  • Run make check-deps to verify binaries are available
  • Some tests require a Unix-like environment

License

This project is open source and available under the MIT License.

Acknowledgments

  • Model Context Protocol - The protocol enabling AI-tool interactions
  • FastMCP - The Python framework for building MCP servers
  • uv - An extremely fast Python package installer and resolver

File Search Server

  • fd - A simple, fast and user-friendly alternative to find
  • fzf - A command-line fuzzy finder

Fuzzy Search Server

  • ripgrep - Recursively search directories for text patterns
  • fzf - A command-line fuzzy finder
  • PyMuPDF - Python bindings for MuPDF for PDF processing (optional)
  • ripgrep-all - ripgrep, but also search in PDFs, E-Books, Office documents (optional)
  • pandoc - Universal markup converter (optional)

SQLite Server

  • SQLite - Self-contained, serverless, zero-configuration SQL database engine

Related Servers