diff --git a/CHANGELOG.md b/CHANGELOG.md index 987a68a..ac1a441 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ Tags follow `v{opencode_version}[letter]` — bare tag for the first build on a - **Feature:** Add MemPalace local-first AI memory system to base image. Provides 29 MCP tools for semantic search over conversation history, knowledge graph queries, and agent diaries. Palace data persists via optional `devbox-palace` named volume, ChromaDB embedding model cache via `devbox-chroma-cache`. No API keys required. - **Feature:** Auto-register mempalace MCP server in generated opencode.json (when mempalace is installed and config is auto-generated from OPENCODE_PROVIDER). +- **Feature:** Add official Gitea MCP server (`gitea-mcp`) to base image. Provides 50+ MCP tools for Gitea API (repos, issues, PRs, releases, Actions). Disabled by default — requires `GITEA_ACCESS_TOKEN` and `GITEA_HOST` env vars. ## v1.14.28 — 2026-04-26 diff --git a/DOCKER_HUB.md b/DOCKER_HUB.md index 4a9fdd4..988be57 100644 --- a/DOCKER_HUB.md +++ b/DOCKER_HUB.md @@ -490,7 +490,7 @@ To override with your host's own files, uncomment the matching bind-mount lines - **opencode** — AI coding assistant - **Node.js 22** — for npx-based MCP servers - **AWS CLI v2** — SSO and Bedrock authentication -- **Dev tools** — git, git-lfs, git-crypt, age, ssh, ripgrep, fd, fzf, bat, eza, zoxide, uv, rustup, mempalace, jq, make, gcc, g++, curl, wget, neovim 0.12, tmux, htop, tree, rsync +- **Dev tools** — git, git-lfs, git-crypt, age, ssh, ripgrep, fd, fzf, bat, eza, zoxide, uv, rustup, mempalace, gitea-mcp, jq, make, gcc, g++, curl, wget, neovim 0.12, tmux, htop, tree, rsync - **Non-root user** — runs as `developer` with UID auto-matched to workspace owner (sudo available) ### OMOS image (`latest-omos`) diff --git a/Dockerfile b/Dockerfile index 2e62742..bae2607 100644 --- a/Dockerfile +++ b/Dockerfile @@ -122,6 +122,14 @@ RUN ARCH=$(case "${TARGETARCH}" in amd64) echo "x86_64" ;; arm64) echo "aarch64" curl -fsSL "https://static.rust-lang.org/rustup/dist/${ARCH}-unknown-linux-gnu/rustup-init" -o /usr/local/bin/rustup-init && \ chmod +x /usr/local/bin/rustup-init +# gitea-mcp — MCP server for Gitea API (official, Go binary) +ARG GITEA_MCP_VERSION=1.1.0 +RUN ARCH=$(case "${TARGETARCH}" in amd64) echo "x86_64" ;; arm64) echo "arm64" ;; *) echo "x86_64" ;; esac) && \ + curl -fsSL "https://gitea.com/gitea/gitea-mcp/releases/download/v${GITEA_MCP_VERSION}/gitea-mcp_Linux_${ARCH}.tar.gz" \ + | tar -xz -C /usr/local/bin/ gitea-mcp && \ + chmod +x /usr/local/bin/gitea-mcp && \ + gitea-mcp --version + # Set locale — generate common UTF-8 locales (override via LANG/LC_ALL env vars) # To add more locales, run: sudo sed -i '/.UTF-8/s/^# //g' /etc/locale.gen && sudo locale-gen RUN sed -i -E '/(en_US|en_GB|sv_SE|da_DK|nb_NO|fi_FI|de_DE|fr_FR|es_ES|it_IT|pt_BR|nl_NL|pl_PL|ja_JP|ko_KR|zh_CN)\.UTF-8/s/^# //g' /etc/locale.gen && locale-gen diff --git a/README.md b/README.md index af25774..6eec796 100644 --- a/README.md +++ b/README.md @@ -510,6 +510,38 @@ Both volumes are commented out by default in `docker-compose.yml` — uncomment **Air-gapped environments:** pre-populate the `devbox-chroma-cache` volume with the `all-MiniLM-L6-v2/` model contents. The palace volume needs no pre-population. +## Gitea MCP server + +The image includes the [official Gitea MCP server](https://gitea.com/gitea/gitea-mcp) (`gitea-mcp`), providing 50+ MCP tools for interacting with self-hosted Gitea instances — repositories, issues, pull requests, releases, branches, wiki, and Actions. + +### Setup + +1. Create a Personal Access Token on your Gitea instance (Settings → Applications → Generate Token, scopes: `repo`, `read:user`). + +2. Add to your `.env`: + ```env + GITEA_HOST=https://your-gitea-instance.example.com + GITEA_ACCESS_TOKEN=your_token_here + ``` + +3. Enable the gitea MCP server in your `opencode.json`: + ```json + { + "mcp": { + "gitea": { + "type": "local", + "command": ["gitea-mcp", "-t", "stdio", "--host", "{env:GITEA_HOST}"], + "environment": { + "GITEA_ACCESS_TOKEN": "{env:GITEA_ACCESS_TOKEN}" + }, + "enabled": true + } + } + } + ``` + +The server is installed but disabled by default — it requires authentication to be useful. + ## Shell defaults The image ships a baked `.bash_aliases` and `.inputrc` with quality-of-life defaults. On first container start they are copied from `/etc/skel-devbox/` into `/home/developer/` **only if the target file does not already exist** — so host bind-mounts and any version you've customized inside the container are never overwritten on upgrade. diff --git a/docker-compose.shared.yml b/docker-compose.shared.yml index 25a915a..bf5074e 100644 --- a/docker-compose.shared.yml +++ b/docker-compose.shared.yml @@ -36,6 +36,8 @@ services: - .env environment: - TERM=xterm-256color + - GITEA_ACCESS_TOKEN=${GITEA_ACCESS_TOKEN:-} + - GITEA_HOST=${GITEA_HOST:-} volumes: # Host workspace — user's project directory - ${WORKSPACE_PATH:-~/src}:/workspace diff --git a/docker-compose.yml b/docker-compose.yml index 5c7b83d..29b4e5f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -33,6 +33,9 @@ services: - .env environment: - TERM=xterm-256color + - GITHUB_PERSONAL_ACCESS_TOKEN=${GITHUB_PERSONAL_ACCESS_TOKEN:-} + - GITEA_ACCESS_TOKEN=${GITEA_ACCESS_TOKEN:-} + - GITEA_HOST=${GITEA_HOST:-} volumes: # Host workspace — mount your project here - ${WORKSPACE_PATH:-.}:/workspace diff --git a/entrypoint-user.sh b/entrypoint-user.sh index a1e168b..4da8d4b 100644 --- a/entrypoint-user.sh +++ b/entrypoint-user.sh @@ -93,21 +93,33 @@ EOF ;; esac - # Add MemPalace MCP server if mempalace is installed - if command -v mempalace &>/dev/null && command -v python3 &>/dev/null; then - # Use python3 to merge the mcp block into the existing JSON + # Add MCP servers for installed tools + if command -v python3 &>/dev/null; then python3 -c " -import json, sys +import json, shutil with open('$CONFIG_FILE') as f: config = json.load(f) -config.setdefault('mcp', {})['mempalace'] = { - 'type': 'local', - 'command': ['python3', '-m', 'mempalace.mcp_server'] -} +mcp = config.setdefault('mcp', {}) + +# MemPalace — local AI memory (if installed) +if shutil.which('mempalace'): + mcp['mempalace'] = { + 'type': 'local', + 'command': ['python3', '-m', 'mempalace.mcp_server'] + } + +# Gitea — self-hosted Git forge API (if installed) +if shutil.which('gitea-mcp'): + mcp['gitea'] = { + 'type': 'local', + 'command': ['gitea-mcp', '-t', 'stdio'], + 'enabled': False + } + with open('$CONFIG_FILE', 'w') as f: json.dump(config, f, indent=2) f.write('\n') -" 2>/dev/null && echo "MemPalace MCP server added to opencode config." +" 2>/dev/null && echo "MCP servers registered in opencode config." fi fi