- Improved test suite with environment isolation - All 82 tests passing
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
pip install gitea-mcp \
--extra-index-url https://gitea.hotserv.cloud/api/packages/personal-projects/pypi/simple
From Source
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
# 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
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_REPOis 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)
- Add to
.mcp.json:
{
"mcpServers": {
"gitea": {
"command": "python",
"args": ["-m", "gitea_mcp.server"]
}
}
}
- Set environment variables:
export GITEA_API_TOKEN="your-token"
export GITEA_REPO="owner/repo" # for project mode
- Use in Claude Code:
Create an issue about performance optimization with the 'enhancement' label.
Programmatic Import
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:
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
python -m venv .venv
source .venv/bin/activate # or: .venv\Scripts\activate (Windows)
pip install -e ".[dev]"
Testing
# 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
pip install build
python -m build
Publishing to Gitea PyPI
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, notserver.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 v9.1.0
Original location: mcp-servers/gitea/ v1.3.0
Module renamed: mcp_server → gitea_mcp
Contributing
- Create a feature branch:
git checkout -b feat/your-feature - Make your changes and test:
pytest tests/ - Create a pull request with a clear description
License
MIT