claudeandClaude Opus 5.5 8416babf19
Build and push image / build (push) Successful in 1m27s
Initial gitea-mcpo-docker image
Wraps the official gitea-mcp server (binary copied from
docker.gitea.com/gitea-mcp-server:1.7.0) and serves it two ways from one
container:

- :8000 mcpo (OpenAPI) for Open WebUI, using the container's service
  token and guarded by MCPO_API_KEY.
- :8080 native streamable-HTTP MCP at /mcp for coding agents, with the
  service token stripped so each client must send its own Gitea token.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 13:01:25 +01:00
2026-09-27 13:01:25 +01:00
2026-09-27 13:01:25 +01:00
2026-09-27 13:01:25 +01:00

gitea-mcpo-docker

A single Docker image that exposes the official Gitea MCP server in two ways at once:

Port Protocol For Gitea identity
8000 OpenAPI, via mcpo Open WebUI The container's service token (GITEA_ACCESS_TOKEN)
8080 Native MCP (streamable HTTP) at /mcp Coding agents (Claude Code etc.) Each client's own token, sent as Authorization: Bearer <token>

Both are served by the same gitea-mcp binary: mcpo spawns it as a stdio child, and a second instance runs in gitea-mcp's own HTTP mode.

Build

docker build -t gitea-mcpo-docker .

Run

docker run -p 8000:8000 -p 8080:8080 \
  -e GITEA_HOST=https://code.aneur.in \
  -e GITEA_ACCESS_TOKEN=<service-account token> \
  -e MCPO_API_KEY=some-secret \
  gitea-mcpo-docker

Open WebUI

Add a tool server pointing at http://<host>:8000, with bearer auth set to MCPO_API_KEY. Interactive API docs are at http://<host>:8000/docs (and /openapi.json). These are served without authentication even when MCPO_API_KEY is set; only the tool endpoints themselves require it.

Claude Code (or any MCP client)

claude mcp add --transport http gitea http://<host>:8080/mcp \
  --header "Authorization: Bearer <your Gitea token>"

The HTTP endpoint never falls back to the service token: GITEA_ACCESS_TOKEN and GITEA_ACCESS_TOKEN_FILE are stripped from that process's environment. A request without a token gets a token is required tool error, and a request with one acts as that token's user. Commits, comments and PRs are therefore attributed to whichever account the client's token belongs to.

Environment variables

Variable Effect
GITEA_HOST Required. Base URL of the Gitea instance, e.g. https://code.aneur.in.
GITEA_ACCESS_TOKEN Token that the mcpo side (Open WebUI) uses. Not visible to the :8080 MCP endpoint.
GITEA_ACCESS_TOKEN_FILE Alternative to the above: path to a file holding the token (e.g. a Docker secret).
MCPO_API_KEY If set, mcpo tool endpoints require Authorization: Bearer <value>. If unset, mcpo serves unauthenticated.
GITEA_READONLY true exposes only read-only tools, on both ports.
GITEA_SCOPES / GITEA_TOOLS Comma-separated allowlist of tool scopes / tool names, on both ports (see gitea-mcp --help).
GITEA_INSECURE true ignores TLS certificate errors talking to Gitea.
GITEA_DEBUG true enables gitea-mcp debug logging.
MCPO_PORT Port mcpo listens on. Default 8000.
MCP_PORT Port the native MCP endpoint listens on. Default 8080.
ENABLE_MCPO / ENABLE_MCP Set either to false to run only the other side. Both default true.

MCP_MODE is ignored: gitea-mcp would otherwise let it override the transport, so the entrypoint unsets it.

Process supervision

entrypoint.sh runs both servers under tini. If either one exits, the other is stopped and the container exits non-zero, so the orchestrator restarts the whole thing rather than leaving it half up. docker stop shuts both down promptly.

Known characteristics

  • No TLS termination. This image serves plain HTTP; put a reverse proxy in front of it if you need TLS or network restriction.
  • The :8080 endpoint has no auth of its own. It relies entirely on Gitea tokens: anyone who can reach it and holds a valid Gitea token can use it as that user, and no more than that user could do directly against the Gitea API.
  • gitea-mcp's HTTP endpoint also serves /healthz (unauthenticated).

Pinned revisions

  • gitea-mcp: pinned via ARG GITEA_MCP_VERSION in the Dockerfile. The binary is copied from the official image docker.gitea.com/gitea-mcp-server (tags have no v prefix). When bumping it, check gitea-mcp --help still accepts what entrypoint.sh uses.
  • mcpo: pinned via ARG MCPO_VERSION, with the mcp SDK pinned alongside it via ARG MCP_SDK_VERSION (see the comment in the Dockerfile for why).

CI

.gitea/workflows/docker-build.yml builds and pushes code.aneur.in/cloud/gitea-mcpo-docker:latest on every push to main, first re-tagging the existing :latest as :previous. It logs in to the registry as the triggering user, with the repo secret BUILD_API_TOKEN as the password. The default Gitea Actions token can't write to the package registry on this instance, so that secret must be a personal access token with package-write scope.

S
Description
No description provided
Readme
30 KiB
Languages
Shell 55.9%
Dockerfile 44.1%