#!/bin/sh set -eu # Runs up to two servers in one container, both backed by the same # gitea-mcp binary: # # - mcpo (OpenAPI, for Open WebUI) on $MCPO_PORT, wrapping a stdio # `gitea-mcp` child. That child authenticates to Gitea with the # container's GITEA_ACCESS_TOKEN (or GITEA_ACCESS_TOKEN_FILE). No # passthrough is needed: mcpo builds the spawned child's environment as # {**os.environ, **extra}, so it inherits GITEA_HOST, GITEA_READONLY etc. # # - gitea-mcp's own streamable-HTTP MCP endpoint (for coding clients) on # $MCP_PORT, path /mcp. This one is deliberately started WITHOUT the # service token, so every client must send its own Gitea token as # `Authorization: Bearer `; without one, tool calls fail with # "token is required" rather than silently acting as the service user. # # mcpo's --api-key is a CLI flag, not something it reads from its own # environment, so the command line is built here at container start. : "${GITEA_HOST:?GITEA_HOST must be set, e.g. https://code.aneur.in}" MCPO_PORT="${MCPO_PORT:-8000}" MCP_PORT="${MCP_PORT:-8080}" ENABLE_MCPO="${ENABLE_MCPO:-true}" ENABLE_MCP="${ENABLE_MCP:-true}" # gitea-mcp lets MCP_MODE override its -t flag; make sure it can't. unset MCP_MODE pids="" shutdown() { # shellcheck disable=SC2086 [ -n "$pids" ] && kill -TERM $pids 2>/dev/null || true } trap 'shutdown; wait; exit 143' TERM INT if [ "$ENABLE_MCP" = "true" ]; then env -u GITEA_ACCESS_TOKEN -u GITEA_ACCESS_TOKEN_FILE \ gitea-mcp -t http -p "$MCP_PORT" & pids="$pids $!" fi if [ "$ENABLE_MCPO" = "true" ]; then if [ -n "${MCPO_API_KEY:-}" ]; then mcpo --host 0.0.0.0 --port "$MCPO_PORT" --api-key "$MCPO_API_KEY" -- gitea-mcp -t stdio & else mcpo --host 0.0.0.0 --port "$MCPO_PORT" -- gitea-mcp -t stdio & fi pids="$pids $!" fi if [ -z "$pids" ]; then echo "Both ENABLE_MCPO and ENABLE_MCP are false; nothing to run." >&2 exit 1 fi # Exit as soon as either server dies, taking the other down with it, so the # orchestrator restarts the whole container rather than leaving it half-up. # POSIX sh has no `wait -n`, so poll instead. while :; do for pid in $pids; do if ! kill -0 "$pid" 2>/dev/null; then status=0 wait "$pid" || status=$? echo "Process $pid exited (status $status); stopping container." >&2 shutdown wait || true exit "$(( status == 0 ? 1 : status ))" fi done sleep 1 done