generated from personal-projects/leo-claude-mktplace
feat: add merge tools, tests, and documentation
Added 3 new PR merge tools to complete v1.0.0: - merge_pull_request: Merge PR with 5 strategies (merge, rebase, rebase-merge, squash, fast-forward-only) - get_pr_merge_status: Check if PR is mergeable - cancel_auto_merge: Cancel scheduled auto-merge Changes: - New merge methods in GiteaClient (gitea_client.py) - New async wrappers in PullRequestTools with branch checks (tools/pull_requests.py) - Tool definitions and dispatch routing in tool_registry.py - Boolean type coercion for force_merge and delete_branch parameters - Comprehensive test suite with 18 tests (test_pull_requests.py) - Full documentation: README.md, CHANGELOG.md, CLAUDE.md Features: - 5 merge strategies with full Gitea API support - Branch-aware security enforcement - Type coercion handles MCP string serialization - 100% test coverage for merge operations Result: - Total tools: 39 (7 PR operations + 3 merge = 10 PR tools) - All tests passing (18 new merge tests + 60 existing tests) - Ready for v1.0.0 release Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
315
README.md
Normal file
315
README.md
Normal file
@@ -0,0 +1,315 @@
|
||||
# gitea-mcp
|
||||
|
||||
 
|
||||
|
||||
MCP server providing 39 tools for Gitea repository operations, issue management, and pull request workflows.
|
||||
|
||||
## Overview
|
||||
|
||||
**gitea-mcp** is a Model Context Protocol (MCP) server that brings comprehensive Gitea integration to Claude Code and other MCP-compatible systems. It provides a unified interface for automating repository management, issue tracking, and PR workflows across multiple repositories.
|
||||
|
||||
### Dual-Mode Operation
|
||||
|
||||
- **Project Mode**: Works with a single configured repository (`GITEA_REPO`)
|
||||
- **PMO/Company Mode**: Manages multiple repositories across your Gitea instance with org-level issue aggregation
|
||||
|
||||
### Tool Count: 39 MCP Tools
|
||||
|
||||
Across 7 functional categories:
|
||||
- Issue Management (6 tools)
|
||||
- Label Management (5 tools)
|
||||
- Wiki & Lessons Learned (7 tools)
|
||||
- Milestone Management (5 tools)
|
||||
- Issue Dependencies (4 tools)
|
||||
- Pull Requests (7 tools)
|
||||
- PR Merge Operations (3 tools) — **NEW in v1.0.0**
|
||||
|
||||
## Installation
|
||||
|
||||
### From Gitea PyPI Registry
|
||||
|
||||
```bash
|
||||
pip install gitea-mcp \
|
||||
--extra-index-url https://gitea.hotserv.cloud/api/packages/personal-projects/pypi/simple
|
||||
```
|
||||
|
||||
### From Source
|
||||
|
||||
```bash
|
||||
git clone https://gitea.hotserv.cloud/personal-projects/gitea-mcp.git
|
||||
cd gitea-mcp
|
||||
pip install -e ".[dev]"
|
||||
```
|
||||
|
||||
## Tools Reference
|
||||
|
||||
### Issue Management (6 tools)
|
||||
|
||||
| Tool | Description |
|
||||
|------|-------------|
|
||||
| `list_issues` | List issues with state/label/milestone filters |
|
||||
| `get_issue` | Get specific issue details |
|
||||
| `create_issue` | Create new issue with labels |
|
||||
| `update_issue` | Update issue title, body, state, labels |
|
||||
| `add_comment` | Add comment to issue |
|
||||
| `aggregate_issues` | PMO mode: aggregate issues across multiple repos |
|
||||
|
||||
### Label Management (5 tools)
|
||||
|
||||
| Tool | Description |
|
||||
|------|-------------|
|
||||
| `list_labels` | Get all available labels |
|
||||
| `get_labels` | Get labels with optional filtering |
|
||||
| `suggest_labels` | AI-powered label suggestions for issues |
|
||||
| `create_label` | Create repo-level label |
|
||||
| `create_label_smart` | Create label at appropriate level (org or repo) |
|
||||
|
||||
### Wiki & Lessons Learned (7 tools)
|
||||
|
||||
| Tool | Description |
|
||||
|------|-------------|
|
||||
| `list_wiki_pages` | List all wiki pages |
|
||||
| `get_wiki_page` | Get specific wiki page content |
|
||||
| `create_wiki_page` | Create new wiki page |
|
||||
| `update_wiki_page` | Update existing wiki page |
|
||||
| `create_lesson` | Create structured lessons learned entry |
|
||||
| `search_lessons` | Search lessons by tags or query |
|
||||
| `allocate_rfc_number` | Auto-allocate next RFC number |
|
||||
|
||||
### Milestone Management (5 tools)
|
||||
|
||||
| Tool | Description |
|
||||
|------|-------------|
|
||||
| `list_milestones` | List milestones with state filter |
|
||||
| `get_milestone` | Get specific milestone details |
|
||||
| `create_milestone` | Create new milestone with due date |
|
||||
| `update_milestone` | Update milestone properties |
|
||||
| `delete_milestone` | Delete milestone |
|
||||
|
||||
### Issue Dependencies (4 tools)
|
||||
|
||||
| Tool | Description |
|
||||
|------|-------------|
|
||||
| `list_issue_dependencies` | List issues that block a given issue |
|
||||
| `create_issue_dependency` | Create dependency between issues |
|
||||
| `remove_issue_dependency` | Remove dependency link |
|
||||
| `get_execution_order` | Get parallelizable execution order for issue set |
|
||||
|
||||
### Pull Requests (7 tools)
|
||||
|
||||
| Tool | Description |
|
||||
|------|-------------|
|
||||
| `list_pull_requests` | List PRs with state/label/sort filters |
|
||||
| `get_pull_request` | Get specific PR details |
|
||||
| `get_pr_diff` | Get PR diff as unified diff string |
|
||||
| `get_pr_comments` | Get all comments on a PR |
|
||||
| `create_pr_review` | Create review (approve/request-changes/comment) |
|
||||
| `add_pr_comment` | Add comment to PR |
|
||||
| `create_pull_request` | Create new PR with optional labels |
|
||||
|
||||
### PR Merge Operations (3 tools) — **NEW**
|
||||
|
||||
| Tool | Description |
|
||||
|------|-------------|
|
||||
| `merge_pull_request` | Merge PR with configurable strategy |
|
||||
| `get_pr_merge_status` | Check if PR is mergeable |
|
||||
| `cancel_auto_merge` | Cancel scheduled auto-merge |
|
||||
|
||||
## Merge Strategies
|
||||
|
||||
The `merge_pull_request` tool supports 5 merge strategies:
|
||||
|
||||
| Strategy | Description |
|
||||
|----------|-------------|
|
||||
| `merge` | Create a merge commit (default) |
|
||||
| `rebase` | Rebase commits onto base branch, no merge commit |
|
||||
| `rebase-merge` | Rebase commits then create merge commit |
|
||||
| `squash` | Squash all commits into one |
|
||||
| `fast-forward-only` | Only merge if fast-forward is possible |
|
||||
|
||||
### Example Usage
|
||||
|
||||
```python
|
||||
# Merge with squash strategy
|
||||
await merge_pull_request(
|
||||
pr_number=42,
|
||||
merge_style="squash",
|
||||
delete_branch=True,
|
||||
message="Merge feature branch into main"
|
||||
)
|
||||
|
||||
# Check if mergeable before merging
|
||||
status = await get_pr_merge_status(pr_number=42)
|
||||
if status["mergeable"]:
|
||||
await merge_pull_request(pr_number=42)
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Environment Variables
|
||||
|
||||
```bash
|
||||
GITEA_API_URL # Gitea API URL (default: http://localhost:3000/api/v1)
|
||||
GITEA_API_TOKEN # Gitea personal access token (required)
|
||||
GITEA_MODE # 'project' or 'pmo' (default: auto-detect)
|
||||
GITEA_REPO # 'owner/repo' for project mode (optional in PMO mode)
|
||||
```
|
||||
|
||||
### Auto-Detection
|
||||
|
||||
- **Project Mode**: Activated when `GITEA_REPO` is set or detected from `.git/config`
|
||||
- **PMO Mode**: Activated when GITEA_REPO is not set and user has org-level access
|
||||
|
||||
## Security Model
|
||||
|
||||
### Branch-Aware Access Control
|
||||
|
||||
Read operations (list, get, diff, comments) are allowed on all branches.
|
||||
|
||||
Write operations (create, merge, comment, delete) are restricted:
|
||||
|
||||
- **main/master/prod/*** branches: Read-only
|
||||
- **staging/stage/*** branches: Comments only
|
||||
- **dev/feature/fix/*** branches: Full access
|
||||
- Unknown branches: Read-only (fail-safe)
|
||||
|
||||
Example: Attempting to merge a PR while on `main` branch raises:
|
||||
```
|
||||
PermissionError: Cannot merge PR on branch 'main'.
|
||||
Switch to a development or feature branch to merge PRs.
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Stdio Server Mode (Claude Code)
|
||||
|
||||
1. Add to `.mcp.json`:
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"gitea": {
|
||||
"command": "python",
|
||||
"args": ["-m", "gitea_mcp.server"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. Set environment variables:
|
||||
```bash
|
||||
export GITEA_API_TOKEN="your-token"
|
||||
export GITEA_REPO="owner/repo" # for project mode
|
||||
```
|
||||
|
||||
3. Use in Claude Code:
|
||||
```
|
||||
Create an issue about performance optimization with the 'enhancement' label.
|
||||
```
|
||||
|
||||
### Programmatic Import
|
||||
|
||||
```python
|
||||
from gitea_mcp import get_tool_definitions, create_tool_dispatcher
|
||||
from gitea_mcp.gitea_client import GiteaClient
|
||||
|
||||
# Get all tool definitions
|
||||
tools = get_tool_definitions()
|
||||
|
||||
# Create dispatcher
|
||||
client = GiteaClient()
|
||||
dispatch = create_tool_dispatcher(client)
|
||||
|
||||
# Call tools
|
||||
result = await dispatch("list_issues", {"state": "open"})
|
||||
|
||||
# Or filter by tool name
|
||||
pr_tools = get_tool_definitions(tool_filter=["list_pull_requests", "merge_pull_request"])
|
||||
```
|
||||
|
||||
### HTTP Server (gitea-mcp-remote)
|
||||
|
||||
The tool registry can be used by HTTP transport:
|
||||
|
||||
```python
|
||||
from gitea_mcp.tool_registry import get_tool_definitions, create_tool_dispatcher
|
||||
from gitea_mcp.gitea_client import GiteaClient
|
||||
|
||||
client = GiteaClient()
|
||||
tools = get_tool_definitions()
|
||||
dispatcher = create_tool_dispatcher(client)
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
### Setup
|
||||
|
||||
```bash
|
||||
python -m venv .venv
|
||||
source .venv/bin/activate # or: .venv\Scripts\activate (Windows)
|
||||
pip install -e ".[dev]"
|
||||
```
|
||||
|
||||
### Testing
|
||||
|
||||
```bash
|
||||
# Run all tests
|
||||
pytest tests/ -v
|
||||
|
||||
# Run specific test file
|
||||
pytest tests/test_pull_requests.py -v
|
||||
|
||||
# Run with coverage
|
||||
pytest tests/ --cov=gitea_mcp
|
||||
```
|
||||
|
||||
### Building
|
||||
|
||||
```bash
|
||||
pip install build
|
||||
python -m build
|
||||
```
|
||||
|
||||
### Publishing to Gitea PyPI
|
||||
|
||||
```bash
|
||||
pip install twine
|
||||
|
||||
twine upload \
|
||||
--repository-url https://gitea.hotserv.cloud/api/packages/personal-projects/pypi \
|
||||
dist/*
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
### Core Components
|
||||
|
||||
| Module | Purpose |
|
||||
|--------|---------|
|
||||
| `gitea_client.py` | Synchronous Gitea REST API client |
|
||||
| `config.py` | Configuration loader (env vars, auto-detection) |
|
||||
| `tool_registry.py` | Tool definitions + dispatcher (transport-agnostic) |
|
||||
| `server.py` | MCP stdio server entry point |
|
||||
| `tools/*.py` | Async wrappers with branch-aware access control |
|
||||
|
||||
### Design Patterns
|
||||
|
||||
- **Transport-agnostic**: Tool definitions and dispatch in `tool_registry.py`, not `server.py`
|
||||
- **Async-first**: All tools are async via `run_in_executor`
|
||||
- **Type coercion**: Automatic string→int/bool conversion for MCP serialization
|
||||
- **Branch security**: Checked in async wrappers, not in REST client
|
||||
|
||||
## Origin
|
||||
|
||||
Extracted from [leo-claude-mktplace](https://gitea.hotserv.cloud/personal-projects/leo-claude-mktplace) v9.1.0
|
||||
Original location: `mcp-servers/gitea/` v1.3.0
|
||||
Module renamed: `mcp_server` → `gitea_mcp`
|
||||
|
||||
## Contributing
|
||||
|
||||
1. Create a feature branch: `git checkout -b feat/your-feature`
|
||||
2. Make your changes and test: `pytest tests/`
|
||||
3. Create a pull request with a clear description
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
Reference in New Issue
Block a user