Skip to main content
Glama
README.md
**English** | **[中文](README.zh-CN.md)**

# PR-Agent MCP Server

A MCP (Model Context Protocol) server that exposes [pr-agent](https://github.com/Codium-ai/pr-agent) CLI commands as MCP tools, with optional Gitea webhook integration for automatic PR review. Supports both SSE and StreamableHTTP transports, and can run locally or in Docker.

## Features

- **MCP Tools**: Expose pr-agent commands (`review`, `describe`, `improve`, `ask`, `reflect`, `update_changelog`, `generate_labels`) as MCP tools.
- **Transports**: SSE (`/sse`) and StreamableHTTP (`/mcp`), selectable via `--transport sse|streamable-http|both`.
- **Gitea Webhook**: Automatically trigger review, describe, and improve actions when a new PR is opened in Gitea.
- **HMAC Signature Verification**: Optional webhook signature validation for security.
- **Config Injection**: Automatically loads credentials from `~/.secrets.toml` and injects them into the pr-agent subprocess environment.

## Project Structure

```
pr-agent-mcp/
├── server.py            # Main MCP server and webhook handler
├── run.ps1              # PowerShell startup script (local run)
├── requirements.txt     # Python dependencies
├── Dockerfile           # Multi-stage Docker image definition
├── docker-compose.yml   # Docker Compose service definition
├── push.ps1             # Build & push image to registry
├── .dockerignore        # Exclude files from Docker build context
├── buggy_samples.py     # Intentional bug samples for pr-agent testing
├── test.http            # HTTP test requests (VS Code REST Client / similar)
├── README.md
├── README.zh-CN.md
└── .gitignore
```

## Prerequisites

- **Docker** with Docker Compose (recommended) **or** Python 3.11+ (uses `tomllib`)
- Gitea instance (for webhook integration, optional)
- `~/.secrets.toml` with your provider credentials (see below)

## Configure credentials

Create `~/.secrets.toml` in your user home directory with your provider and LLM credentials:

```toml
[gitea]
url = "http://your-gitea-instance:3000"
token = "your-gitea-personal-access-token"

[openai]
key = "sk-your-openai-api-key"
```

> `SECRETS_TOML_PATH` environment variable overrides the default location (`~/.secrets.toml`). This is used by the Docker image to locate the bind-mounted file.

---

## Docker Deployment (recommended)

### 1. Build and start locally

```powershell
docker compose up -d --build
```

This will:

1. Build the image (multi-stage: installs `pr-agent` and `mcp` dependencies into a venv, installs `git` at runtime).
2. Mount your home directory read-only into the container at `/host-home` so it can read `~/.secrets.toml`.
3. Map host port `9000` to container port `9000`.
4. Start the server with both SSE and StreamableHTTP transports.

> The container mounts `${USERPROFILE}` (the whole home directory) instead of the single `.secrets.toml` file. Mounting a non-existent host file makes Docker create a directory instead, causing `IsADirectoryError` — mounting the parent directory avoids this pitfall.

### 2. Push image to a private registry

```powershell
# Build + tag + push to the default registry (10.10.11.194:1000/pr-agent-mcp:latest)
.\push.ps1

# Push to another registry / with a version tag / skip rebuild
.\push.ps1 -Registry "192.168.1.100:5000" -Tag "v1.0.0" -NoBuild
```

### 3. Run on another machine (e.g. a test server)

Copy `docker-compose.yml` to the target machine and change `build: .` to `image: 10.10.11.194:1000/pr-agent-mcp:latest`, then:

```powershell
docker pull 10.10.11.194:1000/pr-agent-mcp:latest
docker compose up -d
```

Or run directly without a compose file:

```powershell
docker run -d \
  --name pr-agent-mcp \
  -p 9000:9000 \
  -v $env:USERPROFILE:/host-home:ro \
  -e SECRETS_TOML_PATH=/host-home/.secrets.toml \
  --restart unless-stopped \
  10.10.11.194:1000/pr-agent-mcp:latest
```

### Manage the container

```powershell
# View logs
docker compose logs -f

# Stop & remove
docker compose down

# Restart
docker compose restart
```

---

## Local Run (without Docker)

### 1. Install dependencies

```powershell
python -m venv mcp_env
mcp_env\Scripts\activate
pip install -r requirements.txt
```

> `requirements.txt` only contains `mcp` (the MCP framework). **pr-agent is NOT a Python dependency of this server** — it is called as a subprocess via the path configured in `server.py` (or the `PR_AGENT_EXE` environment variable). Make sure pr-agent is already installed somewhere on the machine.

### 2. (Optional) Configure webhook secret

Set `WEBHOOK_SECRET` in `server.py` to the same secret configured in your Gitea webhook settings. Leave it empty to disable signature verification (not recommended for production).

### 3. Start the server

```powershell
.\run.ps1
```

Or directly:

```powershell
python server.py
python server.py --transport sse        # SSE only
python server.py --transport streamable-http  # StreamableHTTP only
```

## Endpoints

| Endpoint     | Method | Description                                      |
|--------------|--------|--------------------------------------------------|
| `/sse`       | GET    | MCP SSE connection endpoint for AI clients       |
| `/mcp`       | POST   | MCP StreamableHTTP endpoint                      |
| `/messages/` | POST   | MCP message transport (SSE mode)                 |
| `/webhook`   | POST   | Gitea webhook receiver for auto PR review        |

## MCP Tools

| Tool               | Description                                                    |
|--------------------|----------------------------------------------------------------|
| `review_pr`        | Review a PR: summary and specific suggestions                 |
| `describe_pr`      | Generate or update PR title and description                   |
| `improve_code`     | Suggest code improvements as PR comments                      |
| `ask_question`     | Ask a question about the PR                                   |
| `reflect`          | Ask the PR author questions about the PR                      |
| `update_changelog` | Update the changelog based on PR contents                     |
| `generate_labels`  | Generate labels for the PR                                    |

## Gitea Webhook Setup

1. In your Gitea repository, go to **Settings → Webhooks → Add Webhook**.
2. Set the target URL to `http://<your-server>:9000/webhook`.
3. Set the HTTP method to `POST` and content type to `application/json`.
4. Optionally set a secret (must match `WEBHOOK_SECRET` in `server.py`).
5. Select the **Pull Request** event with the **Opened** action.

When a PR is opened, the server will automatically run `review`, `describe`, and `improve` actions and post results as PR comments.

## Testing

Use the included `test.http` file with VS Code REST Client or a similar HTTP client to manually test the webhook endpoint.

`buggy_samples.py` contains intentional bugs across multiple categories (security, logic, concurrency, error handling) for testing pr-agent's code review detection capabilities.

## License

Private — internal use only.