Git staging on autopilot — let AI organize your changes into clean, focused commits.
git-polite is a Model Context Protocol (MCP) server that brings intelligent git staging to AI agents. It can automatically organize messy work-in-progress into well-structured commits, or give you surgical precision with line-by-line staging when you need it.
- Autopilot Mode: Let AI analyze your changes and create multiple focused commits automatically
- Line-Level Staging: Stage individual additions and deletions by line number with surgical precision
- Untracked File Support: Stage parts of newly created files (not just modified files)
- Range Selection: Apply multiple changes at once using ranges (e.g.,
0001-0005,0020-0025) - LLM-Friendly Output: Byte-based pagination and smart truncation protect context windows
- Binary File Detection: Automatically detects and skips binary files
- MCP Integration: Works seamlessly with Claude Code, Claude Desktop, and other MCP clients
Run as an MCP server for integration with MCP clients:
uv run git_polite.py mcpThe server exposes four tools:
-
list_changes: List unstaged git changes (including untracked files) as numbered lines
- Smart truncation: Large diffs (>10KB) are automatically truncated to protect LLM context
- Parameters:
paths(optional): List of file paths to filterpage_token(optional): Pagination tokenpage_size_files(optional, default: 50): Max files per pagepage_size_bytes(optional, default: 30KB): Max cumulative bytes per pageunified(optional, default: 20): Context lines around changes
- Output includes
truncated: trueflag for large files with areasonexplaining the truncation - For truncated files, use the
difftool to view complete content
-
diff: View complete diff for a single file without truncation
- Use this for files that are truncated in
list_changesoutput - Returns the same numbered line format as
list_changes, enabling partial staging - Unlike
git diff, this tool provides line numbers required byapply_changes - Never truncates output, suitable for large files with extensive changes
- Parameters:
path(required): File path to view diff forunified(optional, default: 20): Context lines around changes
- Returns: Complete diff with
size_bytesindicating actual output size
- Use this for files that are truncated in
-
apply_changes: Apply selected changes to git index by number (supports partial staging of untracked files)
- Parameters:
path: File path to apply changes tonumbers: Change numbers (format:NNNN,MMMM,PPPP-QQQQ)
- Parameters:
-
auto_commit: Start autopilot mode to organize all changes into focused commits
- Shows recent commit messages for style reference
- Analyzes all unstaged changes and suggests logical groupings
- Guides AI through creating multiple atomic commits from messy WIP
Use uvx to run directly from GitHub:
Claude Desktop Configuration:
{
"mcpServers": {
"git-polite": {
"command": "uvx",
"args": [
"git-polite@git+https://github.com/uneco/mcp-git-polite.git",
"mcp"
]
}
}
}Claude CLI:
claude mcp add -s user git-polite uvx git-polite@git+https://github.com/uneco/mcp-git-polite.git mcpAlternatively, use the Docker image from GitHub Container Registry:
{
"mcpServers": {
"git-polite": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-v",
"${workspaceFolder}:/workspace",
"-w",
"/workspace",
"ghcr.io/uneco/mcp-git-polite:latest",
"mcp"
]
}
}
}- List Phase: The tool parses
git diffoutput (including untracked files viagit diff --no-index) and numbers each addition (+) and deletion (-) sequentially - Truncation Check: Each file's diff size is measured. Files exceeding 10KB are marked as truncated to protect LLM context
- Display: Changes are shown with their numbers, along with surrounding context lines. Files are marked as "added" (untracked), "modified", or "deleted"
- Pagination: Results are paginated based on cumulative byte size (default 30KB per page) to prevent overwhelming the LLM
- Apply Phase: When you specify line numbers, the tool:
- Reads the staged version from git index (or creates new file for untracked files)
- Applies only the selected changes
- Updates the git index with the partial changes
{
"page_token_next": "optional-token",
"files": [
{
"path": "src/main.py",
"binary": false,
"status": "modified",
"lines": [
"0001: + new line 1",
" context line",
"0002: - deleted line",
"0003: + new line 2",
" ..."
]
},
{
"path": "src/new_file.py",
"binary": false,
"status": "added",
"lines": [
"0001: + def hello():",
"0002: + print('Hello')"
]
},
{
"path": "src/refactored_module.py",
"binary": false,
"status": "modified",
"truncated": true,
"reason": "diff too large (45.2 KB, max 10 KB)",
"lines": []
}
],
"stats": {
"files": 3,
"lines": 5,
"truncated_files": 1,
"page_bytes": 4532
}
}When a file shows truncated: true, use the diff tool to view its complete content. The diff tool provides the same numbered line format needed for partial staging, which git diff cannot provide.
{
"applied": [
{
"file": "src/main.py",
"count": 3,
"lines": ["remaining", "unstaged", "changes"],
"unstaged_lines": 5
}
],
"skipped": [],
"stats": {
"files": 1,
"changes_applied": 3,
"changes_skipped": 0
}
}- Python 3.10 or higher
- Git (command-line tool)
- MCP server package (
mcp>=1.10.0)
# Install dependencies
uv sync
# Run tests (if available)
uv run pytest
# Format code
uv run black git_polite.py
# Type check
uv run mypy git_polite.py- AI-Powered Commit Organization: Let AI analyze your WIP and create clean commit history automatically
- Incremental Commits: Break down large changes into logical, atomic commits
- Partial File Staging: Stage only specific lines of a new file while keeping the rest unstaged
- Code Review Preparation: Stage related changes together, even if scattered across files
- Refactoring: Separate formatting changes from logic changes with surgical precision
When you encounter a truncated file (e.g., a large refactored file with many changes):
# Step 1: List all changes
result = list_changes()
# Step 2: Notice a truncated file
# {
# "path": "src/api_client.py",
# "truncated": true,
# "reason": "diff too large (45.2 KB, max 10 KB)",
# "lines": []
# }
# Step 3: View the complete numbered diff
# Use the diff tool (not git diff) because it provides line numbers needed for partial staging
full_diff = diff(path="src/api_client.py")
# Step 4: Selectively stage related changes (e.g., bug fixes separate from refactoring)
apply_changes(path="src/api_client.py", numbers="0001-0050,0120-0135")# Get first page (max 30KB)
page1 = list_changes(page_size_bytes=30720)
# Continue with next page if needed
if page1["page_token_next"]:
page2 = list_changes(page_token=page1["page_token_next"])- Works only with text files (binary files are detected and skipped)
- Line numbers are ephemeral - they change after each apply operation
- Context mismatches (file drift) will cause operations to fail safely
- For untracked files, the entire file content must be present in the working directory
- Large files (>10KB diff) are truncated in
list_changes- usedifftool to view them
MIT License - See LICENSE file for details
Contributions are welcome! Please feel free to submit a Pull Request.
Built with FastMCP and the Model Context Protocol.
