Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ These servers aim to demonstrate MCP features and the official SDKs.
- **[Everything](src/everything)** - Reference / test server with prompts, resources, and tools
- **[Fetch](src/fetch)** - Web content fetching and conversion for efficient LLM usage
- **[Filesystem](src/filesystem)** - Secure file operations with configurable access controls
- **[Git](src/git)** - Tools to read, search, and manipulate Git repositories
- **[Git](src/git)** - Tools to read, search, and manipulate Git repositories with secure auto-discovery
- **[Memory](src/memory)** - Knowledge graph-based persistent memory system
- **[Sequential Thinking](src/sequentialthinking)** - Dynamic and reflective problem-solving through thought sequences
- **[Time](src/time)** - Time and timezone conversion capabilities
Expand Down
98 changes: 97 additions & 1 deletion src/git/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,65 @@ Please note that mcp-server-git is currently in early development. The functiona
- `not_contains` (string, optional): The commit sha that branch should NOT contain. Do not pass anything to this param if no commit sha is specified
- Returns: List of branches

14. `git_discover_repositories`
- Discover git repositories within allowed paths (requires --enable-discovery)
- Inputs:
- `scan_path` (string, optional): Specific path to scan for repositories (must be within MCP roots)
- `force_refresh` (boolean, optional): Clear cache and force fresh scan
- Returns: List of discovered git repositories

## Enhanced Features: Secure Repository Discovery

### Repository Auto-Discovery
The git server now supports secure automatic discovery of git repositories within allowed directories. This feature is **opt-in** and designed with security as the top priority.

#### Key Security Features:
- **Explicit Opt-in**: Discovery must be enabled with `--enable-discovery` flag
- **Bounded Scanning**: Respects MCP session roots and configurable depth limits
- **Pattern Exclusion**: Automatically excludes sensitive directories like `node_modules`, `.venv`
- **Performance Limits**: Timeouts and async scanning prevent performance issues
- **Audit Logging**: All discovery activities are logged for security review
- **Cache Management**: TTL-based caching with secure cleanup

### Enhanced CLI Options

#### Multiple Repository Support
```bash
# Specify multiple repositories explicitly
mcp-server-git --repository /path/to/repo1 --repository /path/to/repo2

# Or use short form
mcp-server-git -r /path/to/repo1 -r /path/to/repo2
```

#### Auto-Discovery Configuration
```bash
# Enable discovery with default settings
mcp-server-git --enable-discovery

# Customize discovery parameters
mcp-server-git --enable-discovery \
--max-discovery-depth 3 \
--discovery-exclude "node_modules" \
--discovery-exclude ".venv" \
--discovery-exclude "target"

# Combine explicit repos with discovery
mcp-server-git -r /important/repo --enable-discovery
```

### Intelligent Repository Resolution
The server now automatically resolves file paths to their containing git repository:
```json
{
"name": "git_status",
"arguments": {
"repo_path": "/workspace/myproject/src/components"
}
}
```
↳ Automatically resolves to `/workspace/myproject` if it contains a `.git` directory

## Installation

### Using uv (recommended)
Expand Down Expand Up @@ -125,7 +184,7 @@ python -m mcp_server_git
Add this to your `claude_desktop_config.json`:

<details>
<summary>Using uvx</summary>
<summary>Using uvx (single repository)</summary>

```json
"mcpServers": {
Expand All @@ -137,6 +196,43 @@ Add this to your `claude_desktop_config.json`:
```
</details>

<details>
<summary>Using uvx with auto-discovery</summary>

```json
"mcpServers": {
"git": {
"command": "uvx",
"args": [
"mcp-server-git",
"--enable-discovery",
"--max-discovery-depth", "2",
"--discovery-exclude", "node_modules",
"--discovery-exclude", ".venv"
]
}
}
```
</details>

<details>
<summary>Using uvx with multiple repositories</summary>

```json
"mcpServers": {
"git": {
"command": "uvx",
"args": [
"mcp-server-git",
"--repository", "path/to/repo1",
"--repository", "path/to/repo2",
"--enable-discovery"
]
}
}
```
</details>

<details>
<summary>Using docker</summary>

Expand Down
27 changes: 23 additions & 4 deletions src/git/src/mcp_server_git/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,20 @@
from pathlib import Path
import logging
import sys
from .server import serve
from .server import serve, DiscoveryConfig

@click.command()
@click.option("--repository", "-r", type=Path, help="Git repository path")
@click.option("--repository", "-r", "repositories", multiple=True, type=Path,
help="Git repository path (can be specified multiple times)")
@click.option("--enable-discovery", is_flag=True, default=False,
help="Enable repository auto-discovery within MCP session roots")
@click.option("--max-discovery-depth", default=2, type=int,
help="Maximum directory depth for auto-discovery (default: 2)")
@click.option("--discovery-exclude", multiple=True,
help="Patterns to exclude from discovery (e.g., 'node_modules', '.venv')")
@click.option("-v", "--verbose", count=True)
def main(repository: Path | None, verbose: bool) -> None:
def main(repositories: tuple[Path, ...], enable_discovery: bool, max_discovery_depth: int,
discovery_exclude: tuple[str, ...], verbose: bool) -> None:
"""MCP Git Server - Git functionality for MCP"""
import asyncio

Expand All @@ -18,7 +26,18 @@ def main(repository: Path | None, verbose: bool) -> None:
logging_level = logging.DEBUG

logging.basicConfig(level=logging_level, stream=sys.stderr)
asyncio.run(serve(repository))

# Convert tuple to list for easier handling
repo_list = list(repositories) if repositories else []

# Create discovery configuration
discovery_config = DiscoveryConfig(
enabled=enable_discovery,
max_depth=max_discovery_depth,
exclude_patterns=list(discovery_exclude)
) if enable_discovery else None

asyncio.run(serve(repo_list, discovery_config))

if __name__ == "__main__":
main()
3 changes: 2 additions & 1 deletion src/git/src/mcp_server_git/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@

from mcp_server_git import main

main()
if __name__ == "__main__":
main()
Loading