You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 9c247df
Browse filesBrowse the repository at this point in the historyBrowse files
ci: re-enable the server Docker image build on stable releases (#1208)
* ci: re-enable the server Docker image build on stable releases
The `build-docker` job has been gated behind `if: false` since the Teams
work; the server edition it builds now ships, so nothing is holding it
back. Re-enable it and make `release` depend on it, so a stable tag never
publishes binaries without a matching container image.
Deviations from the issue's proposal, and why:
- The guard is `startsWith(github.ref, 'refs/tags/v') && !contains(github.ref_name, '-')`,
not the bare tag check. release.yml fires on every `v*` tag including
RCs, and the job pushes `:latest` unconditionally — an RC tag must not
move that pointer. This matches the guard `build`/`release` already use.
- The image is now multi-arch (`linux/amd64,linux/arm64`). The release
already ships an arm64 Linux binary, and container users on Raspberry
Pi / Graviton would otherwise be stuck building it themselves — the
exact problem the issue reports. The Dockerfile cross-compiles from
`$BUILDPLATFORM` via `$TARGETARCH`, so this is a second native build
rather than QEMU emulation.
- Added a build-only `docker-image` job to PR Build. Now that `release`
hard-depends on `build-docker`, a Dockerfile regression would otherwise
first surface at tag time and block the release; this catches it on the
PR instead, and smoke-tests the entrypoint.
Verified locally: both the single-arch and the multi-arch build succeed,
the amd64 image reports `(server) linux/amd64`, `/healthz` returns 200,
and `/ui/` serves the real embedded Vue bundle (not the fallback stub).
Closes#1171
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(ci): gate build-docker on qa-gate before it pushes to GHCR
cmd/release-gate's TestPublishJobsGatedOnQAGate caught this on the first
CI run: the audit skips jobs that can never run (`if: false`), so
un-gating build-docker made it visible as a publisher for the first time
— and its `needs: [build]` closure did not reach the qa-gate job. A tag
whose release qualification gate failed would still have pushed an image
to GHCR, `:latest` pointer included.
`needs: [build, qa-gate]` closes it. No cycle: release -> build-docker ->
qa-gate.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* ci: label the server image, and warn about the data-dir traps
Two things a deep audit of the server edition turned up that bear directly
on this PR:
1. Flipping `if: false` is not sufficient to close#1171. A GHCR package
first created by GITHUB_TOKEN is PRIVATE by default, and this job had
no labels and no visibility step. An anonymous registry probe today
returns 403 for mcpproxy-server — identical to the control probe for a
name that does not exist — while all five scanner sidecars return 200.
So after the first stable tag, the `docker run` command this PR adds to
the install docs would fail with `denied` for the person who filed the
issue.
`org.opencontainers.image.source` links the package to this repo, which
is a prerequisite for the package page and README, but it does NOT make
it public — that is a one-time manual flip in the org's package settings
after the first push. The comment says so, so the next person does not
have to rediscover it.
2. The install docs now warn about the data-dir traps. `MCPPROXY_DATA` and
a bare `--data-dir` both silently wipe the persisted config on every
boot (the override is applied after config resolution, so the config in
the data dir is never read and is then overwritten with a fresh default,
rotating the API key). `MCPPROXY_DATA_DIR`, documented elsewhere as the
preferred form, has no implementation at all. Fixing the loader ordering
is a separate change; documenting the trap is not.
Also clarified that state dies on container REPLACEMENT, not restart —
verified: `docker restart` on the same container reads back the same key.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: docs/getting-started/installation.md
+37Lines changed: 37 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -365,6 +365,43 @@ You can then run `mcpproxy serve` directly, or wire up your own systemd unit mod
365
365
366
366
The systemd unit launches mcpproxy with `--config=/etc/mcpproxy/mcp_config.json --data-dir=/var/lib/mcpproxy` and uses `NoNewPrivileges`, `ProtectSystem=strict`, `PrivateTmp`, and friends.
367
367
368
+
## Docker (Server edition)
369
+
370
+
The Server edition is published as a multi-arch image (`linux/amd64`, `linux/arm64`) on
371
+
every stable release:
372
+
373
+
```bash
374
+
docker run -d --name mcpproxy \
375
+
-p 127.0.0.1:8080:8080 \
376
+
-e MCPPROXY_API_KEY="$(openssl rand -hex 32)" \
377
+
-v mcpproxy-data:/root/.mcpproxy \
378
+
ghcr.io/smart-mcp-proxy/mcpproxy-server:latest
379
+
```
380
+
381
+
-**Tags**: `ghcr.io/smart-mcp-proxy/mcpproxy-server:<version>` (e.g. `v0.64.0`) and `:latest`,
382
+
which always points at the newest stable release. RC builds publish no image.
383
+
-**State survives restarts, not replacement**: `docker restart` keeps everything. Removing and
384
+
re-running the container, upgrading the tag, or rescheduling the pod destroys whatever is not
385
+
on the volume — so mount one before you configure anything.
386
+
-**Don't use `MCPPROXY_DATA` or a bare `--data-dir` to relocate state.** The data-dir override is
387
+
applied after the config file is resolved, so the config in that directory is never read and is
388
+
overwritten with a fresh default (rotating the API key) on every boot. Mount the volume at the
389
+
default `/root/.mcpproxy` path instead. (`MCPPROXY_DATA_DIR`, referenced elsewhere in the docs,
390
+
is not implemented at all.)
391
+
-**Port**: the entrypoint is `mcpproxy serve --listen 0.0.0.0:8080`, so the container listens on
392
+
`8080` inside the network namespace. The `-p 127.0.0.1:8080:8080` above keeps it reachable only
393
+
from the host; drop the `127.0.0.1:` prefix only if you deliberately want it on the network, and
394
+
read [Network exposure: localhost by default](#network-exposure-localhost-by-default) first.
395
+
-**State**: config, the BBolt DB, and the search index live in `/root/.mcpproxy`. Mount a volume
396
+
there or every restart starts from an empty config.
397
+
-**API key**: the REST API and Web UI require one. Set `MCPPROXY_API_KEY` explicitly and keep a
398
+
copy — the image is distroless (no shell), so reading an auto-generated key back out of the
399
+
container is awkward.
400
+
-**Web UI**: `http://localhost:8080/ui/`.
401
+
402
+
Note that this image ships the Server edition binary (`mcpproxy version` reports `(server)`); it is
Copy file name to clipboardExpand all lines: docs/mcp-registry-publishing.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -98,9 +98,9 @@ mcp-publisher status --status deleted \
98
98
## Registry Schema Notes
99
99
100
100
- `version`must be a plain semantic version string (`0.33.1`) — no `v` prefix, no ranges.
101
-
- `packages[]` is empty because none of the supported `registryType` values (`npm`, `pypi`, `oci`, `nuget`, `mcpb`) match MCPProxy's distribution channels (Homebrew tap, GitHub release tarballs, `.deb`/`.rpm`, `go install`). The Docker server-edition image at `ghcr.io/smart-mcp-proxy/mcpproxy-server` is not yet published to releases (gated behind `if: false` in the release workflow).
101
+
- `packages[]`is empty because none of the supported `registryType` values (`npm`, `pypi`, `oci`, `nuget`, `mcpb`) match MCPProxy's distribution channels (Homebrew tap, GitHub release tarballs, `.deb`/`.rpm`, `go install`). The Docker server-edition image at `ghcr.io/smart-mcp-proxy/mcpproxy-server` *is* published on every stable tag, but the server edition speaks Streamable HTTP rather than stdio, so it is not a drop-in `oci` package entry either.
102
102
- `remotes[]` is intentionally **omitted**. mcpproxy runs locally (`mcpproxy serve` exposes Streamable HTTP at `http://localhost:8080/mcp`), but the registry's semantic validation **rejects localhost/private remote URLs** (`invalid-remote-url`) — `remotes[]` is reserved for publicly reachable hosted endpoints. With no public remote and no installable package type, the entry is **discovery-only**: it lists the server, description, and repository link so clients can find it and follow the repo's install instructions.
103
-
- If a Docker image for the server edition is published in a future release, add an `oci` entry to `packages[]` pointing at `ghcr.io/smart-mcp-proxy/mcpproxy-server:{version}` with `"transport": {"type": "stdio"}` and the appropriate `runtimeArguments` for `docker run`. That would upgrade the entry from discovery-only to one-click installable.
103
+
- Adding an `oci` entry to `packages[]` for `ghcr.io/smart-mcp-proxy/mcpproxy-server:{version}` would upgrade the entry from discovery-only to one-click installable, but it needs a transport the registry accepts for a container that serves HTTP on a published port — not `"transport": {"type": "stdio"}`. Revisit once the registry's remote/container transport story covers it.
0 commit comments