feat(mcp-server): 新增容器化部署支持

- 新增 MCP Server 的 Dockerfile、Compose 环境示例与 GHCR 镜像流水线\n- 补充 Podman Quadlet、Kubernetes Kustomize 与 Helm Chart 部署样例\n- 完善 MCP Server 独立 README,补充本地与远端 Agent 接入说明\n\nFixes #618
This commit is contained in:
Syngnat
2026-07-04 21:57:21 +08:00
parent 9e6a56a77b
commit 0cfcfa77d3
39 changed files with 1537 additions and 0 deletions

18
.containerignore Normal file
View File

@@ -0,0 +1,18 @@
.git
.github
.idea
.ace-tool
.playwright-mcp
.superpowers
.worktrees
bin
build
dist
frontend/dist
node_modules
frontend/node_modules
tools/__pycache__
GoNavi-Wails
GoNavi-Wails.exe
optional-driver-agent
optional-driver-agent.exe

18
.dockerignore Normal file
View File

@@ -0,0 +1,18 @@
.git
.github
.idea
.ace-tool
.playwright-mcp
.superpowers
.worktrees
bin
build
dist
frontend/dist
node_modules
frontend/node_modules
tools/__pycache__
GoNavi-Wails
GoNavi-Wails.exe
optional-driver-agent
optional-driver-agent.exe

118
.github/workflows/docker-images.yml vendored Normal file
View File

@@ -0,0 +1,118 @@
name: Docker Images
on:
push:
branches:
- dev
tags:
- 'v*'
concurrency:
group: docker-images-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
packages: write
jobs:
publish:
name: Publish ${{ matrix.image_name }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- image_name: gonavi-mcp-server
dockerfile: Dockerfile.mcp-server
description: GoNavi MCP Server container image
- image_name: gonavi-build-env
dockerfile: Dockerfile.build-env
description: GoNavi Linux build environment image
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Normalize image namespace
id: vars
shell: bash
run: |
set -euo pipefail
echo "owner_lc=$(printf '%s' "${GITHUB_REPOSITORY_OWNER}" | tr '[:upper:]' '[:lower:]')" >> "$GITHUB_OUTPUT"
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ steps.vars.outputs.owner_lc }}/${{ matrix.image_name }}
flavor: |
latest=false
tags: |
type=raw,value=dev-latest,enable=${{ github.ref == 'refs/heads/dev' }}
type=sha,format=short,prefix=dev-,enable=${{ github.ref == 'refs/heads/dev' }}
type=semver,pattern={{version}},enable=${{ startsWith(github.ref, 'refs/tags/v') }}
type=semver,pattern={{major}}.{{minor}},enable=${{ startsWith(github.ref, 'refs/tags/v') }}
type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/v') }}
labels: |
org.opencontainers.image.title=${{ matrix.image_name }}
org.opencontainers.image.description=${{ matrix.description }}
- name: Build smoke image
uses: docker/build-push-action@v6
with:
context: .
file: ${{ matrix.dockerfile }}
platforms: linux/amd64
load: true
tags: codex-smoke/${{ matrix.image_name }}:local
cache-from: type=gha,scope=${{ matrix.image_name }}
- name: Smoke test MCP Server image
if: matrix.image_name == 'gonavi-mcp-server'
shell: bash
run: |
set -euo pipefail
cid="$(docker run -d -p 8765:8765 -e GONAVI_MCP_HTTP_TOKEN=smoke-token codex-smoke/${{ matrix.image_name }}:local http)"
trap 'docker rm -f "$cid" >/dev/null 2>&1 || true' EXIT
for _ in 1 2 3 4 5 6 7 8 9 10; do
if curl --fail --silent http://127.0.0.1:8765/healthz >/dev/null; then
exit 0
fi
sleep 1
done
docker logs "$cid"
echo "MCP Server image smoke test failed" >&2
exit 1
- name: Smoke test build environment image
if: matrix.image_name == 'gonavi-build-env'
shell: bash
run: |
set -euo pipefail
docker run --rm codex-smoke/${{ matrix.image_name }}:local \
bash -lc 'go version && node -v && npm -v && wails version'
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
file: ${{ matrix.dockerfile }}
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha,scope=${{ matrix.image_name }}
cache-to: type=gha,mode=max,scope=${{ matrix.image_name }}

42
Dockerfile.build-env Normal file
View File

@@ -0,0 +1,42 @@
# syntax=docker/dockerfile:1.7
ARG GO_IMAGE=golang:1.24-bookworm
ARG NODE_IMAGE=node:20-bookworm
FROM ${NODE_IMAGE} AS node
FROM ${GO_IMAGE}
ARG WEBKIT_API=4.0
ARG WAILS_VERSION=v2.11.0
ENV DEBIAN_FRONTEND=noninteractive
ENV PATH=/root/go/bin:${PATH}
COPY --from=node /usr/local/ /usr/local/
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
bash \
build-essential \
ca-certificates \
curl \
file \
git \
make \
pkg-config \
python3 \
unzip \
zip \
libgtk-3-dev \
&& if [ "${WEBKIT_API}" = "4.1" ]; then \
apt-get install -y --no-install-recommends libwebkit2gtk-4.1-dev libsoup-3.0-dev; \
else \
apt-get install -y --no-install-recommends libwebkit2gtk-4.0-dev; \
fi \
&& go install github.com/wailsapp/wails/v2/cmd/wails@${WAILS_VERSION} \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /workspace
CMD ["bash"]

42
Dockerfile.mcp-server Normal file
View File

@@ -0,0 +1,42 @@
# syntax=docker/dockerfile:1.7
FROM --platform=$BUILDPLATFORM golang:1.24-bookworm AS builder
ARG TARGETOS=linux
ARG TARGETARCH=amd64
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} \
go build -trimpath -ldflags="-s -w" -o /out/gonavi-mcp-server ./cmd/gonavi-mcp-server
FROM debian:bookworm-slim
RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates tzdata \
&& rm -rf /var/lib/apt/lists/* \
&& useradd --system --create-home --home-dir /var/lib/gonavi --uid 10001 gonavi \
&& mkdir -p /data /var/lib/gonavi/logs \
&& chown -R gonavi:gonavi /data /var/lib/gonavi
COPY --from=builder /out/gonavi-mcp-server /usr/local/bin/gonavi-mcp-server
ENV HOME=/var/lib/gonavi \
GONAVI_DATA_ROOT=/data \
GONAVI_LOG_DIR=/var/lib/gonavi/logs \
GONAVI_MCP_HTTP_ADDR=0.0.0.0:8765 \
GONAVI_MCP_HTTP_PATH=/mcp \
GONAVI_MCP_SCHEMA_ONLY=true
VOLUME ["/data"]
EXPOSE 8765
USER gonavi
ENTRYPOINT ["/usr/local/bin/gonavi-mcp-server"]
CMD ["http"]

View File

@@ -49,6 +49,187 @@ go run ./cmd/gonavi-mcp-server stdio
go build -o .\bin\gonavi-mcp-server.exe .\cmd\gonavi-mcp-server
```
## Docker / Podman / Compose
当前容器化支持仅覆盖 `gonavi-mcp-server`,不包含 Wails 桌面 GUI。
当前支持矩阵:
- Docker Desktop / Linux 服务器 / NAS直接使用 Compose 或 `docker run`
- Podman / Quadlet使用 `deploy/podman/gonavi-mcp-server`
- Kubernetes使用 `deploy/k8s/gonavi-mcp-server`
- Helm使用 `deploy/helm/gonavi-mcp-server`
- 仅构建环境:使用仓库根目录 `Dockerfile.build-env`
- 桌面 GUI 浏览器访问版:当前不提供,此仓库主应用仍是 Wails 桌面程序,不是现成的 Web 服务
仓库根目录已提供以下文件:
- `Dockerfile.mcp-server`
- `docker-compose.mcp-server.yml`
- `docker.mcp-server.env.example`
- `deploy/podman/gonavi-mcp-server/*`
推荐流程:
```bash
cp docker.mcp-server.env.example docker.mcp-server.env
docker compose --env-file docker.mcp-server.env -f docker-compose.mcp-server.yml up -d
```
默认 Compose 会拉取 GHCR 预构建镜像。如果你要基于当前工作区源码本地构建,再叠加:
```bash
docker compose --env-file docker.mcp-server.env \
-f docker-compose.mcp-server.yml \
-f docker-compose.mcp-server.local.yml \
up -d --build
```
其中 `GONAVI_HOST_DATA_ROOT` 必须指向 GoNavi 当前活动数据目录。该目录内至少应包含:
- `connections.json`
- `daily_secrets.json`
- `drivers/`(如果目标连接依赖可选 driver agent
容器内默认会设置:
- `GONAVI_DATA_ROOT=/data`
- `GONAVI_MCP_HTTP_ADDR=0.0.0.0:8765`
- `GONAVI_MCP_HTTP_PATH=/mcp`
`GONAVI_DATA_ROOT` 会覆盖默认活动数据目录解析逻辑,避免宿主机路径与容器内路径不一致时依赖 `storage_root.json` 的绝对路径。
如果你只想手动构建镜像:
```bash
docker build -f Dockerfile.mcp-server -t gonavi-mcp-server:local .
docker run --rm -p 8765:8765 \
-e GONAVI_MCP_HTTP_TOKEN=replace-with-a-random-token \
-e GONAVI_MCP_SCHEMA_ONLY=true \
-e GONAVI_DATA_ROOT=/data \
-v /absolute/path/to/gonavi-data:/data \
gonavi-mcp-server:local http
```
如果你直接使用已发布镜像:
```bash
docker run --rm -p 8765:8765 \
-e GONAVI_MCP_HTTP_TOKEN=replace-with-a-random-token \
-e GONAVI_MCP_SCHEMA_ONLY=true \
-e GONAVI_DATA_ROOT=/data \
-v /absolute/path/to/gonavi-data:/data \
ghcr.io/syngnat/gonavi-mcp-server:latest http
```
### Podman
仓库内还提供了 Podman 原生部署样例:
- `deploy/podman/gonavi-mcp-server/gonavi-mcp-server.env.example`
- `deploy/podman/gonavi-mcp-server/gonavi-mcp-server.container`
- `deploy/podman/gonavi-mcp-server/README.md`
直接运行已发布镜像:
```bash
cp deploy/podman/gonavi-mcp-server/gonavi-mcp-server.env.example ./gonavi-mcp-server.env
podman run -d --name gonavi-mcp-server --replace \
-p 8765:8765 \
--env-file ./gonavi-mcp-server.env \
-v /absolute/path/to/gonavi-data:/data:Z \
ghcr.io/syngnat/gonavi-mcp-server:latest http
```
如果你要基于当前源码本地构建:
```bash
podman build -f Dockerfile.mcp-server -t localhost/gonavi-mcp-server:local .
podman run -d --name gonavi-mcp-server --replace \
-p 8765:8765 \
--env-file ./gonavi-mcp-server.env \
-v /absolute/path/to/gonavi-data:/data:Z \
localhost/gonavi-mcp-server:local http
```
其中:
- `gonavi-mcp-server.env``deploy/podman/gonavi-mcp-server/gonavi-mcp-server.env.example` 初始化
- `:Z` 适用于开启 SELinux 的宿主机;未启用 SELinux 可去掉
- 更适合长期运行的方式见 [deploy/podman/gonavi-mcp-server/README.md](../../deploy/podman/gonavi-mcp-server/README.md) 中的 Quadlet 示例
`podman compose` 本身依赖外部 compose provider所以仓库对 Podman 的主支持路径是 `podman run` 与 Quadlet而不是假设所有环境都能直接复用 Compose。
## Kubernetes
仓库内置了最小 K8s 示例:
- `deploy/k8s/gonavi-mcp-server/kustomization.yaml`
- `deploy/k8s/gonavi-mcp-server/base/deployment.yaml`
- `deploy/k8s/gonavi-mcp-server/base/service.yaml`
- `deploy/k8s/gonavi-mcp-server/README.md`
- `deploy/k8s/gonavi-mcp-server/overlays/*`
推荐先从现有 GoNavi 数据目录生成 Secret
```bash
kubectl create namespace gonavi
kubectl -n gonavi create secret generic gonavi-mcp-server-data \
--from-file=connections.json=/absolute/path/to/gonavi-data/connections.json \
--from-file=daily_secrets.json=/absolute/path/to/gonavi-data/daily_secrets.json \
--from-literal=GONAVI_MCP_HTTP_TOKEN=replace-with-a-random-token
kubectl apply -k deploy/k8s/gonavi-mcp-server
```
如果需要 NAS hostPath、可选 driver agent PVC、Ingress或两者组合可直接使用 `overlays/nas-hostpath``overlays/drivers-pvc``overlays/ingress``overlays/ingress-with-drivers-pvc`
更完整的说明见 [deploy/k8s/gonavi-mcp-server/README.md](../../deploy/k8s/gonavi-mcp-server/README.md)。
## Helm
如果你希望把镜像、Secret、Ingress、hostPath / PVC 挂载做成参数化部署,而不是维护多份 Kustomize overlay可直接使用
- `deploy/helm/gonavi-mcp-server`
快速安装:
```bash
helm upgrade --install gonavi-mcp-server deploy/helm/gonavi-mcp-server -n gonavi --create-namespace
```
Chart 详细说明见 [deploy/helm/gonavi-mcp-server/README.md](../../deploy/helm/gonavi-mcp-server/README.md)。
## Docker / Podman Build Environment
如果你的目标不是运行 MCP而是给 Linux 服务器 / NAS / CI 准备一套可重复的 Wails 构建环境,可直接使用仓库根目录的 `Dockerfile.build-env`
```bash
docker build -f Dockerfile.build-env -t gonavi-build-env:local .
docker run --rm -it -v "$PWD:/workspace" -w /workspace gonavi-build-env:local bash
```
如果你使用 Podman也可以直接执行
```bash
podman build -f Dockerfile.build-env -t localhost/gonavi-build-env:local .
podman run --rm -it -v "$PWD:/workspace" -w /workspace localhost/gonavi-build-env:local bash
```
镜像内已预装 Go、Node、Wails CLI、GTK3 与 WebKitGTK 开发依赖,适合执行:
```bash
wails build
```
这个镜像默认安装 WebKitGTK 4.0 构建依赖,适合作为通用 Linux / NAS 构建环境。镜像基座支持多架构,`amd64` / `arm64` 会跟随容器平台。
预构建镜像会发布到 GHCR
- `ghcr.io/syngnat/gonavi-mcp-server:latest`
- `ghcr.io/syngnat/gonavi-build-env:latest`
它只负责构建 Linux 产物,不会把 Wails 主程序变成浏览器版服务。
远程 Agent 使用 Streamable HTTP 时必须设置 bearer token
```powershell

View File

@@ -0,0 +1,7 @@
apiVersion: v2
name: gonavi-mcp-server
description: Helm chart for deploying GoNavi MCP Server
type: application
version: 0.1.0
appVersion: "latest"
kubeVersion: ">=1.24.0-0"

View File

@@ -0,0 +1,94 @@
# GoNavi MCP Server Helm Chart
这个 Chart 用来部署 `gonavi-mcp-server`,覆盖当前仓库 K8s 示例里的几类常见场景:
- 基于现有 Secret 直接部署
- 通过 Helm values 内联创建测试用 Secret
- 启用 Ingress
- 追加 `drivers/` PVC
- NAS / k3s 单机节点直接挂宿主机数据目录
Chart 目录:
- `Chart.yaml`
- `values.yaml`
- `values-examples/*.yaml`
- `templates/*.yaml`
## 1. 默认安装
默认值假设你已经有一个现成 Secret
- 名称:`gonavi-mcp-server-data`
- 至少包含:
- `connections.json`
- `daily_secrets.json`
- `GONAVI_MCP_HTTP_TOKEN`
安装命令:
```bash
helm upgrade --install gonavi-mcp-server deploy/helm/gonavi-mcp-server -n gonavi --create-namespace
```
## 2. 直接创建测试用 Secret
如果只是本地验证模板或快速试跑,可以使用示例 values
```bash
helm upgrade --install gonavi-mcp-server deploy/helm/gonavi-mcp-server \
-n gonavi --create-namespace \
-f deploy/helm/gonavi-mcp-server/values-examples/inline-secret.yaml
```
这个示例只适合最小联调,不适合真实生产连接数据。
## 3. 常用示例
启用 Ingress
```bash
helm upgrade --install gonavi-mcp-server deploy/helm/gonavi-mcp-server \
-n gonavi --create-namespace \
-f deploy/helm/gonavi-mcp-server/values-examples/ingress.yaml
```
挂载 drivers PVC
```bash
helm upgrade --install gonavi-mcp-server deploy/helm/gonavi-mcp-server \
-n gonavi --create-namespace \
-f deploy/helm/gonavi-mcp-server/values-examples/drivers-pvc.yaml
```
同时启用 Ingress 与 drivers PVC
```bash
helm upgrade --install gonavi-mcp-server deploy/helm/gonavi-mcp-server \
-n gonavi --create-namespace \
-f deploy/helm/gonavi-mcp-server/values-examples/ingress-with-drivers-pvc.yaml
```
NAS / k3s hostPath
```bash
helm upgrade --install gonavi-mcp-server deploy/helm/gonavi-mcp-server \
-n gonavi --create-namespace \
-f deploy/helm/gonavi-mcp-server/values-examples/nas-hostpath.yaml
```
## 4. 关键参数
- `image.repository` / `image.tag`
- `secret.create`
- `secret.name`
- `data.mode=secret|hostPath|pvc`
- `drivers.mode=none|pvc|hostPath`
- `ingress.enabled`
## 5. 约束
- `data.mode=secret`Secret 必须能提供 `connections.json``daily_secrets.json`
- `data.mode=hostPath` 时,宿主机目录需要包含 GoNavi 活动数据目录内容
- `drivers.mode!=none` 时,会在 `/data/drivers` 追加独立挂载
- Chart 默认只部署 MCP Server不部署桌面 GUI

View File

@@ -0,0 +1,49 @@
{{- define "gonavi-mcp-server.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- define "gonavi-mcp-server.fullname" -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- $name := include "gonavi-mcp-server.name" . -}}
{{- if contains $name .Release.Name -}}
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{- define "gonavi-mcp-server.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" -}}
{{- end -}}
{{- define "gonavi-mcp-server.labels" -}}
helm.sh/chart: {{ include "gonavi-mcp-server.chart" . }}
app.kubernetes.io/name: {{ include "gonavi-mcp-server.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end -}}
{{- define "gonavi-mcp-server.selectorLabels" -}}
app.kubernetes.io/name: {{ include "gonavi-mcp-server.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end -}}
{{- define "gonavi-mcp-server.namespace" -}}
{{- default .Release.Namespace .Values.namespaceOverride -}}
{{- end -}}
{{- define "gonavi-mcp-server.secretName" -}}
{{- if .Values.secret.name -}}
{{- .Values.secret.name -}}
{{- else -}}
{{- include "gonavi-mcp-server.fullname" . -}}
{{- end -}}
{{- end -}}
{{- define "gonavi-mcp-server.serviceName" -}}
{{- include "gonavi-mcp-server.fullname" . -}}
{{- end -}}

View File

@@ -0,0 +1,130 @@
{{- $dataMode := .Values.data.mode -}}
{{- $driversMode := .Values.drivers.mode -}}
{{- if not (or (eq $dataMode "secret") (eq $dataMode "hostPath") (eq $dataMode "pvc")) -}}
{{- fail "data.mode must be one of: secret, hostPath, pvc" -}}
{{- end -}}
{{- if not (or (eq $driversMode "none") (eq $driversMode "pvc") (eq $driversMode "hostPath")) -}}
{{- fail "drivers.mode must be one of: none, pvc, hostPath" -}}
{{- end -}}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "gonavi-mcp-server.fullname" . }}
namespace: {{ include "gonavi-mcp-server.namespace" . }}
labels:
{{- include "gonavi-mcp-server.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "gonavi-mcp-server.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "gonavi-mcp-server.selectorLabels" . | nindent 8 }}
{{- with .Values.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
containers:
- name: gonavi-mcp-server
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
args:
- http
{{- range .Values.mcp.extraArgs }}
- {{ . | quote }}
{{- end }}
ports:
- name: http
containerPort: {{ .Values.service.port }}
protocol: TCP
env:
- name: GONAVI_DATA_ROOT
value: {{ .Values.mcp.dataRoot | quote }}
- name: GONAVI_LOG_DIR
value: {{ .Values.mcp.logDir | quote }}
- name: GONAVI_MCP_HTTP_ADDR
value: {{ .Values.mcp.httpAddr | quote }}
- name: GONAVI_MCP_HTTP_PATH
value: {{ .Values.mcp.httpPath | quote }}
- name: GONAVI_MCP_SCHEMA_ONLY
value: {{ ternary "true" "false" .Values.mcp.schemaOnly | quote }}
- name: GONAVI_MCP_HTTP_TOKEN
valueFrom:
secretKeyRef:
name: {{ include "gonavi-mcp-server.secretName" . }}
key: {{ .Values.secret.tokenKey }}
{{- with .Values.mcp.extraEnv }}
{{- toYaml . | nindent 12 }}
{{- end }}
volumeMounts:
- name: gonavi-data
mountPath: {{ .Values.data.mountPath | quote }}
readOnly: true
{{- if ne $driversMode "none" }}
- name: gonavi-drivers
mountPath: {{ .Values.drivers.mountPath | quote }}
readOnly: true
{{- end }}
readinessProbe:
httpGet:
path: /healthz
port: http
initialDelaySeconds: 3
periodSeconds: 10
livenessProbe:
httpGet:
path: /healthz
port: http
initialDelaySeconds: 10
periodSeconds: 20
resources:
{{- toYaml .Values.resources | nindent 12 }}
securityContext:
{{- toYaml .Values.containerSecurityContext | nindent 12 }}
volumes:
- name: gonavi-data
{{- if eq $dataMode "secret" }}
projected:
sources:
- secret:
name: {{ include "gonavi-mcp-server.secretName" . }}
items:
- key: {{ .Values.secret.connectionsJsonKey }}
path: connections.json
- key: {{ .Values.secret.dailySecretsJsonKey }}
path: daily_secrets.json
{{- else if eq $dataMode "hostPath" }}
hostPath:
path: {{ required "data.hostPath.path is required when data.mode=hostPath" .Values.data.hostPath.path | quote }}
type: {{ default "Directory" .Values.data.hostPath.type | quote }}
{{- else if eq $dataMode "pvc" }}
persistentVolumeClaim:
claimName: {{ required "data.pvc.claimName is required when data.mode=pvc" .Values.data.pvc.claimName | quote }}
{{- end }}
{{- if eq $driversMode "pvc" }}
- name: gonavi-drivers
persistentVolumeClaim:
claimName: {{ required "drivers.pvc.claimName is required when drivers.mode=pvc" .Values.drivers.pvc.claimName | quote }}
{{- else if eq $driversMode "hostPath" }}
- name: gonavi-drivers
hostPath:
path: {{ required "drivers.hostPath.path is required when drivers.mode=hostPath" .Values.drivers.hostPath.path | quote }}
type: {{ default "Directory" .Values.drivers.hostPath.type | quote }}
{{- end }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}

View File

@@ -0,0 +1,34 @@
{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ include "gonavi-mcp-server.fullname" . }}
namespace: {{ include "gonavi-mcp-server.namespace" . }}
labels:
{{- include "gonavi-mcp-server.labels" . | nindent 4 }}
{{- with .Values.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
ingressClassName: {{ .Values.ingress.className | quote }}
{{- with .Values.ingress.tls }}
tls:
{{- toYaml . | nindent 4 }}
{{- end }}
rules:
{{- range .Values.ingress.hosts }}
- host: {{ .host | quote }}
http:
paths:
{{- range .paths }}
- path: {{ .path | quote }}
pathType: {{ .pathType | quote }}
backend:
service:
name: {{ include "gonavi-mcp-server.serviceName" $ }}
port:
number: {{ $.Values.service.port }}
{{- end }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,27 @@
{{- if .Values.secret.create }}
apiVersion: v1
kind: Secret
metadata:
name: {{ include "gonavi-mcp-server.secretName" . }}
namespace: {{ include "gonavi-mcp-server.namespace" . }}
labels:
{{- include "gonavi-mcp-server.labels" . | nindent 4 }}
type: Opaque
stringData:
{{ .Values.secret.tokenKey }}: {{ required "secret.stringData.token is required when secret.create=true" .Values.secret.stringData.token | quote }}
{{- if eq .Values.data.mode "secret" }}
{{ .Values.secret.connectionsJsonKey }}: |
{{ required "secret.stringData.connectionsJson is required when data.mode=secret and secret.create=true" .Values.secret.stringData.connectionsJson | nindent 4 }}
{{ .Values.secret.dailySecretsJsonKey }}: |
{{ required "secret.stringData.dailySecretsJson is required when data.mode=secret and secret.create=true" .Values.secret.stringData.dailySecretsJson | nindent 4 }}
{{- else }}
{{- if .Values.secret.stringData.connectionsJson }}
{{ .Values.secret.connectionsJsonKey }}: |
{{ .Values.secret.stringData.connectionsJson | nindent 4 }}
{{- end }}
{{- if .Values.secret.stringData.dailySecretsJson }}
{{ .Values.secret.dailySecretsJsonKey }}: |
{{ .Values.secret.stringData.dailySecretsJson | nindent 4 }}
{{- end }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,20 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "gonavi-mcp-server.serviceName" . }}
namespace: {{ include "gonavi-mcp-server.namespace" . }}
labels:
{{- include "gonavi-mcp-server.labels" . | nindent 4 }}
{{- with .Values.service.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
type: {{ .Values.service.type }}
selector:
{{- include "gonavi-mcp-server.selectorLabels" . | nindent 4 }}
ports:
- name: http
port: {{ .Values.service.port }}
targetPort: http
protocol: TCP

View File

@@ -0,0 +1,4 @@
drivers:
mode: pvc
pvc:
claimName: gonavi-drivers

View File

@@ -0,0 +1,19 @@
ingress:
enabled: true
className: nginx
hosts:
- host: gonavi-mcp.example.com
paths:
- path: /mcp
pathType: Prefix
- path: /healthz
pathType: Prefix
tls:
- secretName: gonavi-mcp-server-tls
hosts:
- gonavi-mcp.example.com
drivers:
mode: pvc
pvc:
claimName: gonavi-drivers

View File

@@ -0,0 +1,14 @@
ingress:
enabled: true
className: nginx
hosts:
- host: gonavi-mcp.example.com
paths:
- path: /mcp
pathType: Prefix
- path: /healthz
pathType: Prefix
tls:
- secretName: gonavi-mcp-server-tls
hosts:
- gonavi-mcp.example.com

View File

@@ -0,0 +1,13 @@
secret:
create: true
stringData:
token: replace-with-a-random-token
connectionsJson: |
{
"connections": []
}
dailySecretsJson: |
{
"schemaVersion": 1,
"connections": {}
}

View File

@@ -0,0 +1,10 @@
data:
mode: hostPath
hostPath:
path: /volume1/docker/gonavi/data
type: Directory
secret:
create: true
stringData:
token: replace-with-a-random-token

View File

@@ -0,0 +1,99 @@
nameOverride: ""
fullnameOverride: ""
namespaceOverride: ""
replicaCount: 1
image:
repository: ghcr.io/syngnat/gonavi-mcp-server
tag: latest
pullPolicy: IfNotPresent
service:
type: ClusterIP
port: 8765
annotations: {}
mcp:
dataRoot: /data
logDir: /var/lib/gonavi/logs
httpAddr: 0.0.0.0:8765
httpPath: /mcp
schemaOnly: true
extraArgs: []
extraEnv: []
secret:
create: false
name: gonavi-mcp-server-data
tokenKey: GONAVI_MCP_HTTP_TOKEN
connectionsJsonKey: connections.json
dailySecretsJsonKey: daily_secrets.json
stringData:
token: ""
connectionsJson: ""
dailySecretsJson: ""
data:
mode: secret
mountPath: /data
hostPath:
path: /volume1/docker/gonavi/data
type: Directory
pvc:
claimName: ""
drivers:
mode: none
mountPath: /data/drivers
pvc:
claimName: gonavi-drivers
hostPath:
path: /volume1/docker/gonavi/drivers
type: Directory
ingress:
enabled: false
className: nginx
annotations:
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
hosts:
- host: gonavi-mcp.example.com
paths:
- path: /mcp
pathType: Prefix
- path: /healthz
pathType: Prefix
tls:
- secretName: gonavi-mcp-server-tls
hosts:
- gonavi-mcp.example.com
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
podAnnotations: {}
podSecurityContext:
runAsNonRoot: true
runAsUser: 10001
runAsGroup: 10001
seccompProfile:
type: RuntimeDefault
containerSecurityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
nodeSelector: {}
tolerations: []
affinity: {}

View File

@@ -0,0 +1,151 @@
# GoNavi MCP Server Kubernetes 示例
这个目录提供 `gonavi-mcp-server` 的最小 K8s 部署清单,适合:
- Linux 服务器上的单集群部署
- NAS 自带 K8s / k3s / k8s-lite 环境
- 需要把 GoNavi MCP 通过 Ingress / Gateway 暴露给远端 Agent 的场景
如果你希望通过 values 参数统一控制镜像、Secret、Ingress、PVC/hostPath而不是维护多份 overlay请直接使用 [deploy/helm/gonavi-mcp-server](../../helm/gonavi-mcp-server)。
目录结构:
- `kustomization.yaml`:基础部署入口
- `base/kustomization.yaml`:基础资源集合
- `overlays/nas-hostpath`:直接挂 NAS / 单机节点上的 GoNavi 数据目录
- `base/deployment.yaml` / `base/service.yaml`:基础资源
- `overlays/drivers-pvc`:为 `/data/drivers` 增加 PVC 挂载
- `overlays/ingress`:增加 Ingress 暴露 `/mcp`
- `overlays/ingress-with-drivers-pvc`:同时启用 Ingress 和 drivers PVC
## 前提
容器仍然依赖 GoNavi 的活动数据目录。至少要准备:
- `connections.json`
- `daily_secrets.json`
如果目标连接依赖可选 driver agent还需要额外挂载 `/data/drivers`
`base/deployment.yaml` 默认镜像指向:
```text
ghcr.io/syngnat/gonavi-mcp-server:latest
```
如果你要跟随 `dev` 分支,可以改成:
```text
ghcr.io/syngnat/gonavi-mcp-server:dev-latest
```
如果你要使用自建镜像,再按下面方式覆盖 `image`
- 在当前节点可访问的 Docker / Podman / containerd 环境中构建并导入这个镜像
- 把镜像推送到你的私有仓库,并同步修改 `base/deployment.yaml` 里的 `image`
例如:
```bash
docker build -f Dockerfile.mcp-server -t gonavi-mcp-server:local .
# or
podman build -f Dockerfile.mcp-server -t localhost/gonavi-mcp-server:local .
```
## 1. 创建 Secret
推荐直接从现有 GoNavi 数据文件生成:
```bash
kubectl create secret generic gonavi-mcp-server-data \
--from-file=connections.json=/absolute/path/to/gonavi-data/connections.json \
--from-file=daily_secrets.json=/absolute/path/to/gonavi-data/daily_secrets.json \
--from-literal=GONAVI_MCP_HTTP_TOKEN=replace-with-a-random-token
```
如需单独 namespace请先执行
```bash
kubectl create namespace gonavi
kubectl -n gonavi create secret generic gonavi-mcp-server-data \
--from-file=connections.json=/absolute/path/to/gonavi-data/connections.json \
--from-file=daily_secrets.json=/absolute/path/to/gonavi-data/daily_secrets.json \
--from-literal=GONAVI_MCP_HTTP_TOKEN=replace-with-a-random-token
```
## 2. 应用清单
```bash
kubectl apply -k deploy/k8s/gonavi-mcp-server
```
如果使用独立 namespace请先把 YAML 里的 `namespace` 改成你的目标值,或自行用 `kustomize` / Helm 做二次封装。
清单内已经带了基础安全上下文和默认资源配额;如果你的连接数量、对象规模或并发访问更高,建议按实际负载调整 `resources`
### 常用 Overlay
仅基础部署:
```bash
kubectl apply -k deploy/k8s/gonavi-mcp-server
```
需要可选 driver agent
```bash
kubectl apply -k deploy/k8s/gonavi-mcp-server/overlays/drivers-pvc
```
NAS / k3s 单机节点直接挂宿主机目录:
```bash
kubectl apply -k deploy/k8s/gonavi-mcp-server/overlays/nas-hostpath
```
需要对外暴露 `/mcp`
```bash
kubectl apply -k deploy/k8s/gonavi-mcp-server/overlays/ingress
```
同时需要 Ingress 与 drivers PVC
```bash
kubectl apply -k deploy/k8s/gonavi-mcp-server/overlays/ingress-with-drivers-pvc
```
应用 overlay 前,记得先改里面的占位值,例如:
- `overlays/ingress/ingress.yaml` 里的域名、TLS Secret、`ingressClassName`
- `overlays/drivers-pvc/patch-deployment.yaml` 里的 PVC 名称 `gonavi-drivers`
- `overlays/nas-hostpath/patch-deployment.yaml` 里的宿主机目录 `/volume1/docker/gonavi/data`
`nas-hostpath` overlay 会直接把整个 GoNavi 数据目录挂到 `/data`,因此 `connections.json``daily_secrets.json``drivers/` 都从宿主机目录读取;此时仍建议保留 `GONAVI_MCP_HTTP_TOKEN` 的 Secret 注入,不要把 token 直接硬编码进 Deployment。
## 3. 校验
```bash
kubectl get pods -n gonavi
kubectl get svc -n gonavi
kubectl port-forward -n gonavi svc/gonavi-mcp-server 8765:8765
curl -H "Authorization: Bearer replace-with-a-random-token" http://127.0.0.1:8765/healthz
```
`/healthz` 返回 `ok` 说明 Pod 已对外提供 HTTP 服务。
## 4. 暴露给远端 Agent
- 集群内使用:直接访问 `http://gonavi-mcp-server.gonavi.svc.cluster.local:8765/mcp`
- 集群外使用:通过 Ingress / Gateway / 反向代理暴露 `/mcp`
- 远端 Agent 请求头:`Authorization: Bearer <你的 token>`
## 5. drivers 挂载
当前示例默认只挂载 `connections.json``daily_secrets.json`。如果保存连接里包含 Dameng、ClickHouse、DuckDB 等依赖 driver agent 的数据源,请在 Deployment 中额外补一个卷,把宿主机或 PVC 中的 `drivers/` 目录挂载到:
```text
/data/drivers
```
否则对应连接会因为缺少 driver agent 无法使用。

View File

@@ -0,0 +1,89 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: gonavi-mcp-server
namespace: gonavi
labels:
app.kubernetes.io/name: gonavi-mcp-server
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: gonavi-mcp-server
template:
metadata:
labels:
app.kubernetes.io/name: gonavi-mcp-server
spec:
securityContext:
runAsNonRoot: true
runAsUser: 10001
runAsGroup: 10001
seccompProfile:
type: RuntimeDefault
containers:
- name: gonavi-mcp-server
# 如需跟随 dev 分支,可改成 ghcr.io/syngnat/gonavi-mcp-server:dev-latest
image: ghcr.io/syngnat/gonavi-mcp-server:latest
imagePullPolicy: IfNotPresent
args:
- http
ports:
- name: http
containerPort: 8765
protocol: TCP
env:
- name: GONAVI_DATA_ROOT
value: /data
- name: GONAVI_LOG_DIR
value: /var/lib/gonavi/logs
- name: GONAVI_MCP_HTTP_ADDR
value: 0.0.0.0:8765
- name: GONAVI_MCP_HTTP_PATH
value: /mcp
- name: GONAVI_MCP_SCHEMA_ONLY
value: "true"
- name: GONAVI_MCP_HTTP_TOKEN
valueFrom:
secretKeyRef:
name: gonavi-mcp-server-data
key: GONAVI_MCP_HTTP_TOKEN
volumeMounts:
- name: gonavi-data
mountPath: /data
readOnly: true
readinessProbe:
httpGet:
path: /healthz
port: http
initialDelaySeconds: 3
periodSeconds: 10
livenessProbe:
httpGet:
path: /healthz
port: http
initialDelaySeconds: 10
periodSeconds: 20
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
volumes:
- name: gonavi-data
projected:
sources:
- secret:
name: gonavi-mcp-server-data
items:
- key: connections.json
path: connections.json
- key: daily_secrets.json
path: daily_secrets.json

View File

@@ -0,0 +1,6 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml

View File

@@ -0,0 +1,15 @@
apiVersion: v1
kind: Service
metadata:
name: gonavi-mcp-server
namespace: gonavi
labels:
app.kubernetes.io/name: gonavi-mcp-server
spec:
selector:
app.kubernetes.io/name: gonavi-mcp-server
ports:
- name: http
port: 8765
targetPort: http
protocol: TCP

View File

@@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- base

View File

@@ -0,0 +1,8 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
patches:
- path: patch-deployment.yaml

View File

@@ -0,0 +1,18 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: gonavi-mcp-server
namespace: gonavi
spec:
template:
spec:
containers:
- name: gonavi-mcp-server
volumeMounts:
- name: gonavi-drivers
mountPath: /data/drivers
readOnly: true
volumes:
- name: gonavi-drivers
persistentVolumeClaim:
claimName: gonavi-drivers

View File

@@ -0,0 +1,33 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: gonavi-mcp-server
namespace: gonavi
annotations:
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
spec:
ingressClassName: nginx
tls:
- hosts:
- gonavi-mcp.example.com
secretName: gonavi-mcp-server-tls
rules:
- host: gonavi-mcp.example.com
http:
paths:
- path: /mcp
pathType: Prefix
backend:
service:
name: gonavi-mcp-server
port:
number: 8765
- path: /healthz
pathType: Prefix
backend:
service:
name: gonavi-mcp-server
port:
number: 8765

View File

@@ -0,0 +1,9 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
- ingress.yaml
patches:
- path: patch-deployment.yaml

View File

@@ -0,0 +1,18 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: gonavi-mcp-server
namespace: gonavi
spec:
template:
spec:
containers:
- name: gonavi-mcp-server
volumeMounts:
- name: gonavi-drivers
mountPath: /data/drivers
readOnly: true
volumes:
- name: gonavi-drivers
persistentVolumeClaim:
claimName: gonavi-drivers

View File

@@ -0,0 +1,33 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: gonavi-mcp-server
namespace: gonavi
annotations:
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
spec:
ingressClassName: nginx
tls:
- hosts:
- gonavi-mcp.example.com
secretName: gonavi-mcp-server-tls
rules:
- host: gonavi-mcp.example.com
http:
paths:
- path: /mcp
pathType: Prefix
backend:
service:
name: gonavi-mcp-server
port:
number: 8765
- path: /healthz
pathType: Prefix
backend:
service:
name: gonavi-mcp-server
port:
number: 8765

View File

@@ -0,0 +1,6 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
- ingress.yaml

View File

@@ -0,0 +1,8 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
patches:
- path: patch-deployment.yaml

View File

@@ -0,0 +1,14 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: gonavi-mcp-server
namespace: gonavi
spec:
template:
spec:
volumes:
- $patch: replace
name: gonavi-data
hostPath:
path: /volume1/docker/gonavi/data
type: Directory

View File

@@ -0,0 +1,101 @@
# GoNavi MCP Server Podman 示例
这个目录提供 `gonavi-mcp-server` 的 Podman 原生部署入口,覆盖两类常见场景:
- 直接用 `podman run` 在 Linux 服务器 / NAS 上启动
- 用 rootless Quadlet + systemd 做常驻服务
目录内容:
- `gonavi-mcp-server.env.example`:给 `podman run` / Quadlet 共用的容器环境变量示例
- `gonavi-mcp-server.container`Quadlet 示例
前提仍然一样:宿主机 GoNavi 活动数据目录内至少应包含:
- `connections.json`
- `daily_secrets.json`
如果目标连接依赖可选 driver agent还要保证同一数据目录下已有 `drivers/`
## 1. 直接运行已发布镜像
```bash
cp deploy/podman/gonavi-mcp-server/gonavi-mcp-server.env.example ./gonavi-mcp-server.env
```
`GONAVI_MCP_HTTP_TOKEN` 改成随机值后运行:
```bash
podman run -d --name gonavi-mcp-server --replace \
-p 8765:8765 \
--env-file ./gonavi-mcp-server.env \
-v /absolute/path/to/gonavi-data:/data:Z \
ghcr.io/syngnat/gonavi-mcp-server:latest http
```
查看状态:
```bash
podman ps
podman logs -f gonavi-mcp-server
```
如果你的宿主机没有启用 SELinux可把挂载参数末尾的 `:Z` 去掉;如果启用了 SELinux建议保留它。
## 2. 本地源码构建镜像
仓库根目录已经提供 `.containerignore`Podman 会优先读取它来裁剪构建上下文。
```bash
podman build -f Dockerfile.mcp-server -t localhost/gonavi-mcp-server:local .
podman run -d --name gonavi-mcp-server --replace \
-p 8765:8765 \
--env-file ./gonavi-mcp-server.env \
-v /absolute/path/to/gonavi-data:/data:Z \
localhost/gonavi-mcp-server:local http
```
## 3. Rootless Quadlet 常驻服务
Podman Quadlet 适合 Linux 服务器 / NAS 上做 rootless 常驻服务。
把文件放到用户级目录:
```bash
mkdir -p ~/.config/containers/systemd
cp deploy/podman/gonavi-mcp-server/gonavi-mcp-server.container ~/.config/containers/systemd/
cp deploy/podman/gonavi-mcp-server/gonavi-mcp-server.env.example ~/.config/containers/systemd/gonavi-mcp-server.env
```
然后修改两处:
- `~/.config/containers/systemd/gonavi-mcp-server.container` 里的 `Volume=/absolute/path/to/gonavi-data:/data:Z`
- `~/.config/containers/systemd/gonavi-mcp-server.env` 里的 `GONAVI_MCP_HTTP_TOKEN`
启动服务:
```bash
systemctl --user daemon-reload
systemctl --user enable --now gonavi-mcp-server.service
systemctl --user status gonavi-mcp-server.service
journalctl --user -u gonavi-mcp-server.service -f
```
如果你希望用户退出登录后服务仍然保持运行,再执行:
```bash
loginctl enable-linger "$USER"
```
Rootless Quadlet 默认搜索路径是 `~/.config/containers/systemd/`;如果你要做系统级 rootful 部署,可改放到 `/etc/containers/systemd/`
## 4. 关于 Compose
Podman 的 `podman compose` 依赖外部 compose provider。也就是说是否能直接复用仓库根目录的 `docker-compose.mcp-server.yml`,取决于你的 Podman 环境是否已经安装并配置了对应 provider。
因此,这个仓库对 Podman 的主支持路径是:
- `podman run`
- Quadlet推荐长期运行
如果你的环境已经有可用的 compose provider再去复用根目录 Compose 文件即可。

View File

@@ -0,0 +1,22 @@
[Unit]
Description=GoNavi MCP Server (rootless Podman)
Wants=network-online.target
After=network-online.target
[Container]
ContainerName=gonavi-mcp-server
Image=ghcr.io/syngnat/gonavi-mcp-server:latest
Pull=newer
EnvironmentFile=./gonavi-mcp-server.env
# 修改成你的 GoNavi 活动数据目录SELinux 主机建议保留 :Z
Volume=/absolute/path/to/gonavi-data:/data:Z
PublishPort=8765:8765
Exec=http
LogDriver=journald
[Service]
Restart=always
TimeoutStartSec=900
[Install]
WantedBy=default.target

View File

@@ -0,0 +1,15 @@
# 容器内 GoNavi 活动数据根目录。通常不需要修改Volume= 已把宿主机目录挂到 /data。
GONAVI_DATA_ROOT=/data
# 日志目录。默认与镜像内目录保持一致。
GONAVI_LOG_DIR=/var/lib/gonavi/logs
# MCP HTTP 监听地址与路径。
GONAVI_MCP_HTTP_ADDR=0.0.0.0:8765
GONAVI_MCP_HTTP_PATH=/mcp
# 远程 MCP 客户端访问时必须携带的 Bearer Token
GONAVI_MCP_HTTP_TOKEN=replace-with-a-random-token
# true = 只暴露结构查询工具,不注册 execute_sql
GONAVI_MCP_SCHEMA_ONLY=true

View File

@@ -0,0 +1,7 @@
services:
gonavi-mcp-server:
build:
context: .
dockerfile: Dockerfile.mcp-server
image: ${GONAVI_MCP_IMAGE_LOCAL:-gonavi-mcp-server:local}
pull_policy: never

View File

@@ -0,0 +1,20 @@
services:
gonavi-mcp-server:
image: ${GONAVI_MCP_IMAGE:-ghcr.io/syngnat/gonavi-mcp-server:latest}
pull_policy: ${GONAVI_MCP_PULL_POLICY:-missing}
container_name: gonavi-mcp-server
restart: unless-stopped
ports:
- "${GONAVI_MCP_HTTP_PORT:-8765}:8765"
environment:
GONAVI_DATA_ROOT: /data
GONAVI_LOG_DIR: /var/lib/gonavi/logs
GONAVI_MCP_HTTP_ADDR: 0.0.0.0:8765
GONAVI_MCP_HTTP_PATH: ${GONAVI_MCP_HTTP_PATH:-/mcp}
GONAVI_MCP_HTTP_TOKEN: ${GONAVI_MCP_HTTP_TOKEN}
GONAVI_MCP_SCHEMA_ONLY: ${GONAVI_MCP_SCHEMA_ONLY:-true}
volumes:
- type: bind
source: ${GONAVI_HOST_DATA_ROOT}
target: /data
command: ["http"]

View File

@@ -0,0 +1,20 @@
# 宿主机 GoNavi 活动数据目录,目录内至少应包含 connections.json 与 daily_secrets.json
GONAVI_HOST_DATA_ROOT=/absolute/path/to/gonavi-data
# 预构建镜像地址。稳定版通常使用 latest跟随 dev 分支可改成 ghcr.io/syngnat/gonavi-mcp-server:dev-latest
GONAVI_MCP_IMAGE=ghcr.io/syngnat/gonavi-mcp-server:latest
# 预构建镜像拉取策略always / missing / never
GONAVI_MCP_PULL_POLICY=missing
# 远程 MCP 客户端访问时必须携带的 Bearer Token
GONAVI_MCP_HTTP_TOKEN=replace-with-a-random-token
# 宿主机暴露端口
GONAVI_MCP_HTTP_PORT=8765
# MCP HTTP 路径
GONAVI_MCP_HTTP_PATH=/mcp
# true = 只暴露结构查询工具,不注册 execute_sql
GONAVI_MCP_SCHEMA_ONLY=true