Build and push image / build (push) Successful in 1m27s
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>
76 lines
2.4 KiB
Bash
76 lines
2.4 KiB
Bash
#!/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 <token>`; 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
|