latte fa30153c0d
Some checks failed
lint / lint (push) Has been cancelled
test / test (push) Has been cancelled
Enhance Docker workflow with gated publish
Expand workflow triggers to push/pull_request on main and dev and to PR
reviews. Run lint/test only for non-review events or when a review is
approved. Add a docker-test job that smoke-tests the built image. Add a
docker-publish job that resolves SHA and stable tags (latest/dev),
builds
the releasable image, and optionally pushes when PUSH_IMAGE=true. Update
docs/deployment.md
2026-02-27 11:02:48 +01:00
.
2026-01-29 19:53:36 +01:00
.
2026-01-29 19:53:36 +01:00

AegisGitea-MCP

Security-first MCP server for self-hosted Gitea with per-user OAuth2/OIDC authentication.

AegisGitea-MCP exposes MCP tools over HTTP/SSE and validates each user token against Gitea so tool access follows each user's actual repository permissions.

Securing MCP with Gitea OAuth

1) Create a Gitea OAuth2 application

  1. Open https://git.hiddenden.cafe/user/settings/applications (or admin application settings).
  2. Create an OAuth2 app.
  3. Set redirect URI to the ChatGPT callback URL shown after creating a New App.
  4. Save the app and keep:
    • Client ID
    • Client Secret

Required scopes:

  • read:repository
  • write:repository (only needed when using write tools)

2) Configure this MCP server

cp .env.example .env

Set OAuth-first values:

GITEA_URL=https://git.hiddenden.cafe
OAUTH_MODE=true
GITEA_OAUTH_CLIENT_ID=<your-client-id>
GITEA_OAUTH_CLIENT_SECRET=<your-client-secret>
OAUTH_EXPECTED_AUDIENCE=<optional; defaults to client id>

3) Configure ChatGPT New App

In ChatGPT New App:

  • MCP server URL: https://<your-mcp-domain>/mcp/sse
  • Authentication: OAuth
  • OAuth client ID: Gitea OAuth app client ID
  • OAuth client secret: Gitea OAuth app client secret

After creation, copy the ChatGPT callback URL and add it to the Gitea OAuth app redirect URIs.

4) OAuth-protected MCP behavior

The server publishes protected-resource metadata:

  • GET /.well-known/oauth-protected-resource

Example response:

{
  "resource": "https://git.hiddenden.cafe",
  "authorization_servers": ["https://git.hiddenden.cafe"],
  "bearer_methods_supported": ["header"],
  "scopes_supported": ["read:repository", "write:repository"],
  "resource_documentation": "https://hiddenden.cafe/docs/mcp-gitea"
}

If a tool call is missing/invalid auth, MCP endpoints return 401 with:

WWW-Authenticate: Bearer resource_metadata="https://<mcp-host>/.well-known/oauth-protected-resource", scope="read:repository"

Architecture

ChatGPT App
  -> Authorization Code Flow
  -> Gitea OAuth2/OIDC (issuer: https://git.hiddenden.cafe)
  -> Access token
  -> MCP Server (/mcp/sse, /mcp/tool/call)
     -> OIDC discovery + JWKS cache
     -> Scope enforcement (read:repository / write:repository)
     -> Per-request Gitea API calls with Authorization: Bearer <user token>

Example curl

Protected resource metadata:

curl -s https://<mcp-host>/.well-known/oauth-protected-resource | jq

Expected 401 challenge when missing token:

curl -i https://<mcp-host>/mcp/tool/call \
  -H "Content-Type: application/json" \
  -d '{"tool":"list_repositories","arguments":{}}'

Authenticated tool call:

curl -s https://<mcp-host>/mcp/tool/call \
  -H "Authorization: Bearer <user_access_token>" \
  -H "Content-Type: application/json" \
  -d '{"tool":"list_repositories","arguments":{}}'

Threat model

  • Shared bot tokens are dangerous:
    • one leaked token can expose all repositories reachable by that bot account.
    • blast radius is repository-wide and cross-user.
  • Token-in-URL is insecure:
    • URLs leak via logs, proxies, browser history, and referers.
    • bearer tokens must be sent in Authorization headers only.
  • Per-user OAuth reduces lateral access:
    • each call runs as the signed-in user.
    • users only see repositories they already have permission for in Gitea.

CI/CD

Gitea workflows were added under .gitea/workflows/:

  • lint.yml: Ruff + formatting + mypy.
  • test.yml: lint + pytest + enforced coverage (>=80%).
  • docker.yml: lint+test gated Docker build, SHA tag, latest tag on main.

Docker hardening

docker/Dockerfile uses a multi-stage build, non-root runtime user, production env flags, minimal runtime dependencies, and a healthcheck.

Commands

  • make test
  • make lint
  • make format
  • make docker-build
  • make docker-up

Documentation

  • docs/api-reference.md
  • docs/security.md
  • docs/configuration.md
  • docs/deployment.md
  • docs/write-mode.md
Description
AegisGitea MCP is a private, security-first MCP (Model Context Protocol) server that enables controlled, auditable, read-only AI access to a self-hosted Gitea environment. The system allows ChatGPT (Business / Developer environment) to inspect repositories, code, commits, issues, and pull requests only through explicit MCP tool calls, while all access control is dynamically managed through a dedicated bot user inside Gitea itself.
https://gitea-mcp.hiddenden.cafe
Readme MIT 481 KiB
Languages
Python 98.2%
Makefile 0.8%
Shell 0.6%
Dockerfile 0.4%