# gitea-mcp ![Version](https://img.shields.io/badge/version-1.0.0-blue) ![Python](https://img.shields.io/badge/python-3.10%2B-green) 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