Skip to main content
Glama
README.md
# git-mcp

An MCP server that lets an AI agent inspect and interact with a local Git repository.

## Features

- **Git tools**: status, log, branches, create commits (via GitPython)
- **File tools**: list, read, write, inspect files in the workspace
- **Agent-ready**: exposes everything as MCP tools that an LLM agent (LangGraph) can call

## Install

```bash
uv sync
```

Installs the server plus its LangGraph client dependencies.

## Run the server

```bash
uv run project-mcp
```

Or as a stdio MCP server (what MCP clients spawn):

```bash
uv run python -m project_mcp.server
```

You can attach any MCP client — e.g. **MCP Inspector** (`npx @modelcontextprotocol/inspector`) with command `uv run python -m project_mcp.server`.

## Tools

### Git
- `get_status` — current branch and working-tree changes
- `get_log` — recent commit history
- `get_branches` — local and remote branches
- `git_diff` — working-tree / staged / between-commit diffs
- `git_add` — stage changes (explicit paths or all)
- `git_commit` — commit staged changes
- `git_push` — push the current branch to a remote
- `create_commit` — stage-and-commit shortcut

### Files
- `list_dir` — list directory entries
- `read_file` — read file content (optional truncation)
- `write_file` — write content to a file
- `file_info` — size, type, and modification metadata

## Example: LangGraph agent with an LLM (v2)

`examples/langgraph_client.py` is a **LangGraph agent** that spawns the MCP server over stdio, exposes its tools to a model, and answers your questions by calling them.

It talks to **OpenRouter** by default (no OpenAI key needed) and works with any OpenAI-compatible `/v1/chat/completions` endpoint.

### Configure

```bash
cp .env.example .env
# edit .env -> set API_TOKEN (required)
```

`.env` is loaded from the project root (gitignored). Settings:

- `API_TOKEN` — your OpenRouter API key (`https://openrouter.ai/keys`), or a bearer token for another endpoint.
- `MODEL_URL` — OpenAI-compatible base URL. Defaults to `https://openrouter.ai/api/v1`; override for HF endpoints, llama.cpp (`http://localhost:8080/v1`), vLLM (`http://localhost:8000/v1`), LiteLLM, etc.
- `MODEL_NAME` — model id. Default `openrouter/free` (route to a free model). Others: `openai/gpt-4o-mini`, `z-ai/glm-5.2:free`, etc.

### Run

Ask via CLI arg:

```bash
uv run python examples/langgraph_client.py "What is the current git status?"
uv run python examples/langgraph_client.py "Show me the last 3 commits"
```

Or interactively (no arg → prompts you):

```bash
uv run python examples/langgraph_client.py
Ask about the repo:
```

The client uses `langchain-mcp-adapters`, which pins the MCP SDK to v1 (`mcp<2`).

## Example: guarded agent with an LLM intent classifier + safety gate (v3)

`examples/langgraph_client_v3.py` is the v3 agent. It sits between the LLM and the tools and runs **every tool call through an intent classifier and a permission/safety gate**:

```
Intent
  |
  v
Permission/Safety Gate
  |-- read          -> automatic
  |-- modify file   -> approval (interactive y/N)
  |-- git add       -> approval (interactive y/N)
  |-- commit        -> approval (interactive y/N)
  `-- push          -> BLOCKED (only --allow-push unlocks it)
```

How it works:

1. **LLM intent classifier** (`project_mcp.safety.IntentClassifier`) classifies each
   tool call (`name` + `args`) into one of `read` / `modify_file` / `git_add` /
   `commit` / `push`. It asks the configured model first and falls back to a
   deterministic rule map when no model is configured or the answer is unparseable.
2. **Safety gate** (`project_mcp.safety.PermissionGate`) enforces the policy:
   - `read` → allowed automatically.
   - `modify_file` / `git_add` / `commit` → prompts `[y/N]` in an interactive
     terminal. Denied in non-interactive runs unless `--yes` is passed.
   - `push` → **blocked by default**; only `--allow-push` explicitly lifts the block.
   - unknown intent → treated like an approval-gated write.
3. The agent can only reach the MCP server if the gate returns *allow*; otherwise it
   gets a `PERMISSION DENIED` tool message to explain itself.

### Run

```bash
# read-only: no prompt (auto-allowed)
uv run python examples/langgraph_client_v3.py "What is the current git status?"

# write path: interactive y/N approval (or --yes to auto-approve)
uv run python examples/langgraph_client_v3.py "Add notes.txt and commit it"
uv run python examples/langgraph_client_v3.py "Add notes.txt and commit it" --yes

# push: blocked unless explicitly unlocked
uv run python examples/langgraph_client_v3.py "Push to origin"                  # BLOCKED
uv run python examples/langgraph_client_v3.py "Push to origin" --allow-push     # allowed
```

The gate lives in the client (the standard-official place for interactive
approval). The same `IntentClassifier` / `PermissionGate` classes are reusable:
wire them into any agent loop, or point `--yes` at a non-interactive CI run.

### Observability (Opik)

Set `OPIK_API_KEY` in `.env` (or `OPIK_URL` for a self-hosted Opik server) and
the v3 agent auto-instruments **Comet Opik**:

- Every LangGraph run is a trace tagged **`main-llm`** — agent reasoning +
  MCP tool inputs/outputs.
- Every gate decision is a **`guardrail`**-typed span tagged **`security`** with
  `{tool, args}` as input and `{intent, permission, allowed, reason}` as output.

```bash
uv add opik          # dependency already in pyproject.toml
cp .env.example .env # already done? set OPIK_API_KEY
uv run python examples/langgraph_client_v3.py "What changed?"   # -> logged to Opik
```

Disable tracing per-run with `--no-trace`. If neither `OPIK_API_KEY` nor
`OPIK_URL` is set, every observability helper is a no-op and the agent runs
identically (zero added latency/calls).

## Development

```bash
uv run pytest
```

Layout:

```
src/project_mcp/       package source (server, git_tools, file_tools, safety)
tests/                 pytest tests (unit + stdio MCP integration)
examples/              LangGraph agent clients (v2 plain, v3 guarded)
.env.example           model endpoint config template
```

---

## Summary: v1 vs v2 vs v3

This project shows three ways to consume the same MCP server.

**v1 — MCP Inspector**
- A lightweight GUI/debugging client that inspects a server interactively.
- Lets you browse tools, see schemas, and fire individual calls by hand.
- Good for validating a server's surface before wiring an agent.
- Connection: stdio spawn of `project_mcp.server` via inspector config.

**v2 — LangGraph + OpenRouter**
- A programmatic **agent** that connects to the server, grabs its tools, and lets an LLM decide which to call to answer a user question.
- Adds an actual model (OpenRouter `openrouter/free` by default) on top of the MCP tool surface.
- Reusable pattern: MCP server → LangChain tools → LangGraph ReAct agent with any open-source/OpenAI-compatible model.
- Uses `langchain-mcp-adapters`, hence `mcp<2`.

**v3 — LLM intent classifier + permission/safety gate**
- Same agent loop as v2, plus a guard layer between the model and the tools.
- Every tool call is **classified into an intent** (`read` / `modify_file` /
  `git_add` / `commit` / `push`) by a dedicated LLM pass, then **checked against
  the safety policy**: reads run automatically, writes/adds/commits need approval,
  and pushes are blocked unless explicitly unlocked (`--allow-push`).
- The classification + gating logic lives in `project_mcp.safety` and is fully
  unit-tested, so another client or UI can reuse the same gate.

> Note: `langchain-mcp-adapters` currently only supports MCP SDK v1, which is why the project stays on `mcp<2`. If you need the newer MCP SDK v2 (`MCPServer` API), the LangChain adapter has no stable release for it yet.

TDQS

C2.1/5.0

Scored across 8 tools

Disambiguation5/5

The tools fall into two clear groups—Git operations (get_status, get_log, get_branches, create_commit) and file operations (list_dir, read_file, write_file, file_info)—with no meaningful overlap. Each name points to a distinct resource and action, so an agent should rarely misselect.

Naming Consistency4/5

Most tools follow a consistent verb_noun pattern (get_status, get_log, get_branches, create_commit, list_dir, read_file, write_file). file_info is the one outlier because it uses noun_info rather than a verb, but the rest of the set remains predictable.

Tool Count5/5

Eight tools is a well-scoped size for a lightweight Git and file manipulation server. Each tool covers a distinct, useful operation without redundancy or bloat.

Completeness4/5

The set supports a coherent workflow: inspect repository state, browse/edit files, and create commits. It lacks branch creation/checkout and diff/staging operations, but the core status/log/branches/commit/file surface is functional for basic Git workflows.

Maintenance

ActivityMaintained
ResponsivenessNo issues