renamed deploy to examples
This commit is contained in:
5 files changed
+217
-3
No files matched your search
+3
-3
@@ -16,7 +16,7 @@ cd bookstack-mcp
|
|||||||
You should now be able to run this with no errors — all three paths must exist:
|
You should now be able to run this with no errors — all three paths must exist:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ls pyproject.toml bookstack_mcp/server.py deploy/lxc/install.sh
|
ls pyproject.toml bookstack_mcp/server.py scripts/install-lxc.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
## 1. Install
|
## 1. Install
|
||||||
@@ -24,7 +24,7 @@ ls pyproject.toml bookstack_mcp/server.py deploy/lxc/install.sh
|
|||||||
Requires Debian 12+ or Ubuntu 24.04+ (Python 3.11 or newer).
|
Requires Debian 12+ or Ubuntu 24.04+ (Python 3.11 or newer).
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bash deploy/lxc/install.sh
|
bash scripts/install-lxc.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
This creates the `bookstack-mcp` service user, a venv at
|
This creates the `bookstack-mcp` service user, a venv at
|
||||||
@@ -61,7 +61,7 @@ MCP_STATIC_TOKENS=<openssl rand -hex 32>
|
|||||||
```
|
```
|
||||||
|
|
||||||
Add claude.ai later by switching to `MCP_AUTH_MODE=oidc+token` and filling in
|
Add claude.ai later by switching to `MCP_AUTH_MODE=oidc+token` and filling in
|
||||||
the OIDC block — see `deploy/authelia/configuration.snippet.yml`.
|
the OIDC block — see `examples/authelia/configuration.snippet.yml`.
|
||||||
|
|
||||||
## 4. Start
|
## 4. Start
|
||||||
|
|
||||||
|
|||||||
File renamed without changes.
@@ -0,0 +1,53 @@
|
|||||||
|
# Butane config for running bookstack-mcp as a container on Flatcar Container
|
||||||
|
# Linux. Convert to Ignition and hand it to the machine on first boot:
|
||||||
|
#
|
||||||
|
# butane --pretty --strict bookstack-mcp.bu > bookstack-mcp.ign
|
||||||
|
#
|
||||||
|
# Fill in the image reference below (your Gitea registry) and the values in
|
||||||
|
# the env file. systemd's EnvironmentFile= only sets the *unit's* environment
|
||||||
|
# (i.e. what the docker CLI sees), not the container's -- that's why the unit
|
||||||
|
# passes --env-file explicitly to `docker run`.
|
||||||
|
variant: flatcar
|
||||||
|
version: 1.0.0
|
||||||
|
storage:
|
||||||
|
files:
|
||||||
|
- path: /etc/bookstack-mcp.env
|
||||||
|
mode: 0600
|
||||||
|
contents:
|
||||||
|
inline: |
|
||||||
|
BOOKSTACK_URL=https://wiki.example.com
|
||||||
|
BOOKSTACK_TOKEN_ID=
|
||||||
|
BOOKSTACK_TOKEN_SECRET=
|
||||||
|
BOOKSTACK_READ_ONLY=true
|
||||||
|
MCP_HOST=0.0.0.0
|
||||||
|
MCP_PORT=8080
|
||||||
|
MCP_PATH=/mcp
|
||||||
|
MCP_AUTH_MODE=oidc+token
|
||||||
|
MCP_PUBLIC_URL=https://mcp.example.com
|
||||||
|
MCP_STATIC_TOKENS=
|
||||||
|
# See example.env at the project root for the full list of options
|
||||||
|
# (OIDC, GitHub OAuth, allowed users/groups, etc).
|
||||||
|
systemd:
|
||||||
|
units:
|
||||||
|
- name: bookstack-mcp.service
|
||||||
|
enabled: true
|
||||||
|
contents: |
|
||||||
|
[Unit]
|
||||||
|
Description=BookStack MCP Server
|
||||||
|
After=docker.service network-online.target
|
||||||
|
Requires=docker.service
|
||||||
|
Wants=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStartPre=-/usr/bin/docker rm -f bookstack-mcp
|
||||||
|
ExecStartPre=/usr/bin/docker pull git.example.com/owner/bookstack-mcp:latest
|
||||||
|
ExecStart=/usr/bin/docker run --rm --name bookstack-mcp \
|
||||||
|
--env-file /etc/bookstack-mcp.env \
|
||||||
|
-p 8080:8080 \
|
||||||
|
git.example.com/owner/bookstack-mcp:latest
|
||||||
|
ExecStop=/usr/bin/docker stop bookstack-mcp
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=5
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
File renamed without changes.
@@ -0,0 +1,161 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Install the BookStack MCP server into a Debian/Ubuntu LXC container.
|
||||||
|
# Run as root, from inside the container, in the directory containing pyproject.toml:
|
||||||
|
#
|
||||||
|
# bash scripts/install-lxc.sh
|
||||||
|
#
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
APP_DIR=/opt/bookstack-mcp
|
||||||
|
CONF_DIR=/etc/bookstack-mcp
|
||||||
|
SVC_USER=bookstack-mcp
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
|
||||||
|
log() { printf '\033[1;34m==>\033[0m %s\n' "$*"; }
|
||||||
|
die() { printf '\033[1;31mERROR:\033[0m %s\n' "$*" >&2; exit 1; }
|
||||||
|
|
||||||
|
# Find the project root. Normally this script lives at scripts/install-lxc.sh
|
||||||
|
# so the root is one level up, but people often copy the tree around flat, so
|
||||||
|
# check the obvious candidates rather than assuming.
|
||||||
|
find_src() {
|
||||||
|
local candidate
|
||||||
|
for candidate in "$SCRIPT_DIR/.." "$SCRIPT_DIR" "$PWD"; do
|
||||||
|
if [[ -f "$candidate/pyproject.toml" && -d "$candidate/bookstack_mcp" ]]; then
|
||||||
|
(cd "$candidate" && pwd)
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if ! SRC_DIR="$(find_src)"; then
|
||||||
|
die "Can't find the project source (needs pyproject.toml and a bookstack_mcp/ directory).
|
||||||
|
Looked in: $SCRIPT_DIR/.. , $SCRIPT_DIR , $PWD
|
||||||
|
|
||||||
|
Get the whole project into the container, then run the script from its root:
|
||||||
|
git clone <your-repo> /opt/src/bookstack-mcp
|
||||||
|
cd /opt/src/bookstack-mcp
|
||||||
|
bash scripts/install-lxc.sh"
|
||||||
|
fi
|
||||||
|
|
||||||
|
[[ $EUID -eq 0 ]] || die "Run this as root (or with sudo)."
|
||||||
|
|
||||||
|
# The script copies SRC_DIR into APP_DIR, so they must not be the same place.
|
||||||
|
if [[ "$SRC_DIR" == "$APP_DIR" ]]; then
|
||||||
|
die "The source is $APP_DIR, which is also the install target.
|
||||||
|
Keep the source somewhere else and let the installer copy it in:
|
||||||
|
mkdir -p /opt/src && mv $APP_DIR /opt/src/bookstack-mcp
|
||||||
|
cd /opt/src/bookstack-mcp && bash scripts/install-lxc.sh"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Installing from $SRC_DIR"
|
||||||
|
|
||||||
|
# --- Python version check -------------------------------------------------
|
||||||
|
# Needs 3.11+. Debian 12/13 and Ubuntu 24.04 are fine; Debian 11 and
|
||||||
|
# Ubuntu 22.04 ship something older and need a newer python installed first.
|
||||||
|
log "Checking Python version"
|
||||||
|
if ! command -v python3 >/dev/null; then
|
||||||
|
die "python3 not installed. Try: apt install -y python3 python3-venv"
|
||||||
|
fi
|
||||||
|
PY_OK=$(python3 -c 'import sys; print(1 if sys.version_info >= (3,11) else 0)')
|
||||||
|
if [[ "$PY_OK" != "1" ]]; then
|
||||||
|
die "Python $(python3 -V | cut -d' ' -f2) found, but 3.11+ is required.
|
||||||
|
Debian 12+/Ubuntu 24.04+ work out of the box. On older releases install a
|
||||||
|
newer python3 first (e.g. via deadsnakes) and re-run."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- Dependencies ---------------------------------------------------------
|
||||||
|
log "Installing system packages"
|
||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
# A single broken third-party repo shouldn't abort the whole install, so the
|
||||||
|
# update is advisory; only the install itself is allowed to fail the script.
|
||||||
|
apt-get update -qq || log "apt update reported errors, continuing"
|
||||||
|
apt-get install -y -qq python3-venv python3-pip ca-certificates >/dev/null
|
||||||
|
|
||||||
|
# --- Service user ---------------------------------------------------------
|
||||||
|
if ! id -u "$SVC_USER" >/dev/null 2>&1; then
|
||||||
|
log "Creating service user $SVC_USER"
|
||||||
|
useradd --system --home-dir "$APP_DIR" --shell /usr/sbin/nologin "$SVC_USER"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- Application ----------------------------------------------------------
|
||||||
|
log "Installing application to $APP_DIR"
|
||||||
|
mkdir -p "$APP_DIR"
|
||||||
|
rm -rf "$APP_DIR/bookstack_mcp"
|
||||||
|
cp -r "$SRC_DIR/bookstack_mcp" "$APP_DIR/"
|
||||||
|
cp "$SRC_DIR/pyproject.toml" "$APP_DIR/"
|
||||||
|
|
||||||
|
if [[ ! -d "$APP_DIR/venv" ]]; then
|
||||||
|
log "Creating virtualenv"
|
||||||
|
python3 -m venv "$APP_DIR/venv"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Installing Python dependencies (this takes a minute)"
|
||||||
|
"$APP_DIR/venv/bin/pip" install --quiet --upgrade pip
|
||||||
|
"$APP_DIR/venv/bin/pip" install --quiet "$APP_DIR"
|
||||||
|
|
||||||
|
chown -R "$SVC_USER:$SVC_USER" "$APP_DIR"
|
||||||
|
|
||||||
|
# --- Configuration --------------------------------------------------------
|
||||||
|
# Prefer a filled-in .env if one exists, otherwise fall back to the template.
|
||||||
|
ENV_SRC=""
|
||||||
|
for candidate in "$SRC_DIR/.env" "$SRC_DIR/.env.example"; do
|
||||||
|
[[ -f "$candidate" ]] && { ENV_SRC="$candidate"; break; }
|
||||||
|
done
|
||||||
|
[[ -n "$ENV_SRC" ]] || die "Can't find $SRC_DIR/.env or $SRC_DIR/.env.example to seed the config from."
|
||||||
|
|
||||||
|
mkdir -p "$CONF_DIR"
|
||||||
|
# An empty file counts as "not configured" -- a previous failed run can leave
|
||||||
|
# a zero-byte config behind, and silently keeping it is worse than replacing it.
|
||||||
|
if [[ ! -s "$CONF_DIR/env" ]]; then
|
||||||
|
log "Creating $CONF_DIR/env from $(basename "$ENV_SRC")"
|
||||||
|
# systemd EnvironmentFile does not understand quotes or inline comments the
|
||||||
|
# way a shell does, so strip comments and blank lines out of the source.
|
||||||
|
# Write to a temp file first so a failure here can't leave an empty config.
|
||||||
|
grep -vE '^\s*(#|$)' "$ENV_SRC" > "$CONF_DIR/env.tmp"
|
||||||
|
mv "$CONF_DIR/env.tmp" "$CONF_DIR/env"
|
||||||
|
NEW_CONFIG=1
|
||||||
|
else
|
||||||
|
log "Keeping existing $CONF_DIR/env"
|
||||||
|
NEW_CONFIG=0
|
||||||
|
fi
|
||||||
|
chown root:"$SVC_USER" "$CONF_DIR/env"
|
||||||
|
chmod 640 "$CONF_DIR/env"
|
||||||
|
|
||||||
|
# --- systemd --------------------------------------------------------------
|
||||||
|
log "Installing systemd unit"
|
||||||
|
UNIT_SRC=""
|
||||||
|
for candidate in "$SRC_DIR/examples/lxc/bookstack-mcp.service" "$SCRIPT_DIR/bookstack-mcp.service"; do
|
||||||
|
[[ -f "$candidate" ]] && { UNIT_SRC="$candidate"; break; }
|
||||||
|
done
|
||||||
|
[[ -n "$UNIT_SRC" ]] || die "Can't find bookstack-mcp.service"
|
||||||
|
install -m 644 "$UNIT_SRC" /etc/systemd/system/bookstack-mcp.service
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable bookstack-mcp >/dev/null
|
||||||
|
|
||||||
|
echo
|
||||||
|
log "Install complete."
|
||||||
|
echo
|
||||||
|
if [[ "$NEW_CONFIG" == "1" ]]; then
|
||||||
|
cat <<EOF
|
||||||
|
Next steps:
|
||||||
|
|
||||||
|
1. Edit the config and fill in your BookStack details:
|
||||||
|
nano $CONF_DIR/env
|
||||||
|
|
||||||
|
At minimum: BOOKSTACK_URL, BOOKSTACK_TOKEN_ID, BOOKSTACK_TOKEN_SECRET.
|
||||||
|
Generate a Claude Code token with: openssl rand -hex 32
|
||||||
|
|
||||||
|
2. Start it:
|
||||||
|
systemctl start bookstack-mcp
|
||||||
|
systemctl status bookstack-mcp
|
||||||
|
journalctl -u bookstack-mcp -f
|
||||||
|
|
||||||
|
3. Verify locally (401 with a WWW-Authenticate header is the correct answer
|
||||||
|
when auth is enabled):
|
||||||
|
curl -i http://127.0.0.1:8080/mcp
|
||||||
|
EOF
|
||||||
|
else
|
||||||
|
echo " systemctl restart bookstack-mcp"
|
||||||
|
fi
|
||||||
Reference in new issue
Block a user