diff --git a/STATUS.md b/STATUS.md index c9c896f..4e93dbc 100644 --- a/STATUS.md +++ b/STATUS.md @@ -2,7 +2,7 @@ Tracking the setup and validation of MCP/LSP servers via Docker Compose. -Last validated: 2026-02-19 +Last validated: 2026-02-20 ## Repository URLs Verified (2026-02-19) @@ -48,8 +48,10 @@ All 32 vendor repositories have been verified and correctly cloned. CloneVendorR ## Validation Summary -**Working MCP Servers (16 validated with MCP handshake):** +**Working MCP Servers (24 validated with MCP handshake):** +- ✓ actual-mcp: Working (Actual Budget MCP) - requires ACTUAL_SERVER_URL, ACTUAL_PASSWORD, ACTUAL_BUDGET_SYNC_ID env vars - ✓ audiobook-mcp: Working (audiobook-library v1.1.0) - requires AUDIOBOOK_ROOT env var +- ✓ beszel-mcp: Working (beszel-mcp) - requires BESZEL_URL, BESZEL_USERNAME, BESZEL_PASSWORD env vars - ✓ bitwarden-mcp: Working (Bitwarden MCP Server) - requires Bitwarden credentials - ✓ blender-mcp: Working (BlenderMCP v1.25.0) - requires Blender with addon running - ✓ cloudron-mcp: Working (cloudron-mcp v0.1.0) - requires CLOUDRON_URL env var @@ -60,11 +62,17 @@ All 32 vendor repositories have been verified and correctly cloned. CloneVendorR - ✓ freecad-mcp: Working (FreeCADMCP v1.25.0) - requires FreeCAD with addon running - ✓ ghost-mcp: Working (ghost-mcp-ts v1.0.0) - requires Ghost CMS credentials - ✓ gimp-mcp: Working (GimpMCP v1.10.1) - requires GIMP with server running +- ✓ gitea-mcp: Working (gitea-mcp) - requires GITEA_URL and GITEA_TOKEN env vars +- ✓ grafana-mcp: Working (mcp-grafana) - requires GRAFANA_URL and GRAFANA_TOKEN env vars +- ✓ ha-mcp: Working (Home Assistant MCP) - requires HOMEASSISTANT_URL and HOMEASSISTANT_TOKEN env vars - ✓ kubernetes-mcp: Working (mcp-k8s Go binary) - requires kubeconfig mounted at /root/.kube/config +- ✓ limesurvey-mcp: Working (limesurvey-mcp) - requires LIMESURVEY_URL, LIMESURVEY_USERNAME, LIMESURVEY_PASSWORD env vars +- ✓ linkwarden-mcp: Working (linkwarden-mcp v0.0.1) - requires LINKWARDEN_URL and LINKWARDEN_TOKEN env vars - ✓ terraform-mcp: Working (terraform-mcp-server v0.4.0) - requires credentials for HCP Terraform - ✓ matomo-mcp: Working (matomo-mcp-client v1.0.0) - connects to openmost.io hosted service (59 tools, 31 prompts) - ✓ mcp-redmine: Working (Redmine MCP server v1.25.0) - requires REDMINE_URL for actual usage - ✓ paperless-mcp: Working (paperless-ngx v1.0.0) - requires baseUrl/token CLI args +- ✓ superset-mcp: Working (superset-mcp) - requires SUPERSET_URL, SUPERSET_USERNAME, SUPERSET_PASSWORD env vars **Runtime Connection Required (crash before MCP protocol):** - ✗ nextcloud-mcp: Requires reachable OAuth endpoint - crashes on startup with connection refused diff --git a/crush.json b/crush.json index b5fb833..eb6807e 100644 --- a/crush.json +++ b/crush.json @@ -125,6 +125,46 @@ "command": "/home/charles/Projects/KNEL-AIMiddleware/mcp-ansible-wrapper.sh", "timeout": 60 }, + "actual": { + "type": "stdio", + "command": "/home/charles/Projects/KNEL-AIMiddleware/mcp-actual-wrapper.sh", + "timeout": 60 + }, + "beszel": { + "type": "stdio", + "command": "/home/charles/Projects/KNEL-AIMiddleware/mcp-beszel-wrapper.sh", + "timeout": 60 + }, + "gitea": { + "type": "stdio", + "command": "/home/charles/Projects/KNEL-AIMiddleware/mcp-gitea-wrapper.sh", + "timeout": 60 + }, + "grafana": { + "type": "stdio", + "command": "/home/charles/Projects/KNEL-AIMiddleware/mcp-grafana-wrapper.sh", + "timeout": 60 + }, + "homeassistant": { + "type": "stdio", + "command": "/home/charles/Projects/KNEL-AIMiddleware/mcp-ha-wrapper.sh", + "timeout": 60 + }, + "limesurvey": { + "type": "stdio", + "command": "/home/charles/Projects/KNEL-AIMiddleware/mcp-limesurvey-wrapper.sh", + "timeout": 60 + }, + "linkwarden": { + "type": "stdio", + "command": "/home/charles/Projects/KNEL-AIMiddleware/mcp-linkwarden-wrapper.sh", + "timeout": 60 + }, + "superset": { + "type": "stdio", + "command": "/home/charles/Projects/KNEL-AIMiddleware/mcp-superset-wrapper.sh", + "timeout": 60 + }, "postizz": { "type": "stdio", "command": "/home/charles/Projects/KNEL-AIMiddleware/mcp-postizz-wrapper.sh", diff --git a/docker-compose.yml b/docker-compose.yml index f3fc8e9..1b25a08 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -545,6 +545,165 @@ services: profiles: - dev + # ========================================== + # Financial & Budgeting (1 server) + # ========================================== + + # Actual Budget MCP - Budget management + # NOTE: This is a stdio-based MCP server, run on-demand by Crush via docker run + actual-mcp: + image: kneldevstack-aimiddleware-actual-mcp + build: + context: ./vendor/actual-mcp + dockerfile: ../../dockerfiles/actual-mcp/Dockerfile + container_name: kneldevstack-aimiddleware-actual-mcp + restart: "no" + environment: + - ACTUAL_SERVER_URL=${ACTUAL_SERVER_URL} + - ACTUAL_PASSWORD=${ACTUAL_PASSWORD} + - ACTUAL_BUDGET_SYNC_ID=${ACTUAL_BUDGET_SYNC_ID} + profiles: + - ops + + # ========================================== + # System Monitoring (1 server) + # ========================================== + + # Beszel MCP - System monitoring tool + # NOTE: This is a stdio-based MCP server, run on-demand by Crush via docker run + beszel-mcp: + image: kneldevstack-aimiddleware-beszel-mcp + build: + context: ./vendor/beszel-mcp + dockerfile: ../../dockerfiles/beszel-mcp/Dockerfile + container_name: kneldevstack-aimiddleware-beszel-mcp + restart: "no" + environment: + - PYTHONUNBUFFERED=1 + - BESZEL_URL=${BESZEL_URL} + - BESZEL_USERNAME=${BESZEL_USERNAME} + - BESZEL_PASSWORD=${BESZEL_PASSWORD} + profiles: + - ops + + # ========================================== + # Git Hosting (1 server) + # ========================================== + + # Gitea MCP - Git hosting integration + # NOTE: This is a stdio-based MCP server, run on-demand by Crush via docker run + gitea-mcp: + image: kneldevstack-aimiddleware-gitea-mcp + build: + context: ./vendor/gitea-mcp + dockerfile: ../../dockerfiles/gitea-mcp/Dockerfile + container_name: kneldevstack-aimiddleware-gitea-mcp + restart: "no" + environment: + - GITEA_URL=${GITEA_URL} + - GITEA_TOKEN=${GITEA_TOKEN} + profiles: + - ops + + # ========================================== + # Home Automation (1 server) + # ========================================== + + # Home Assistant MCP - Complete HA control + # NOTE: This is a stdio-based MCP server, run on-demand by Crush via docker run + ha-mcp: + image: kneldevstack-aimiddleware-ha-mcp + build: + context: ./vendor/ha-mcp + dockerfile: ../../dockerfiles/ha-mcp/Dockerfile + container_name: kneldevstack-aimiddleware-ha-mcp + restart: "no" + environment: + - PYTHONUNBUFFERED=1 + - HOMEASSISTANT_URL=${HOMEASSISTANT_URL} + - HOMEASSISTANT_TOKEN=${HOMEASSISTANT_TOKEN} + profiles: + - ops + + # ========================================== + # Survey Tools (1 server) + # ========================================== + + # LimeSurvey MCP - Survey management + # NOTE: This is a stdio-based MCP server, run on-demand by Crush via docker run + limesurvey-mcp: + image: kneldevstack-aimiddleware-limesurvey-mcp + build: + context: ./vendor/limesurvey-mcp + dockerfile: ../../dockerfiles/limesurvey-mcp/Dockerfile + container_name: kneldevstack-aimiddleware-limesurvey-mcp + restart: "no" + environment: + - LIMESURVEY_URL=${LIMESURVEY_URL} + - LIMESURVEY_USERNAME=${LIMESURVEY_USERNAME} + - LIMESURVEY_PASSWORD=${LIMESURVEY_PASSWORD} + profiles: + - ops + + # ========================================== + # Bookmark Management (1 server) + # ========================================== + + # Linkwarden MCP - Bookmark management + # NOTE: This is a stdio-based MCP server, run on-demand by Crush via docker run + linkwarden-mcp: + image: kneldevstack-aimiddleware-linkwarden-mcp + build: + context: ./vendor/linkwarden-mcp-server + dockerfile: ../../dockerfiles/linkwarden-mcp/Dockerfile + container_name: kneldevstack-aimiddleware-linkwarden-mcp + restart: "no" + environment: + - LINKWARDEN_URL=${LINKWARDEN_URL} + - LINKWARDEN_TOKEN=${LINKWARDEN_TOKEN} + profiles: + - ops + + # ========================================== + # Observability (1 server) + # ========================================== + + # Grafana MCP - Dashboard and observability + # NOTE: This is a stdio-based MCP server, run on-demand by Crush via docker run + mcp-grafana: + image: kneldevstack-aimiddleware-mcp-grafana + build: + context: ./vendor/mcp-grafana + dockerfile: ../../dockerfiles/mcp-grafana/Dockerfile + container_name: kneldevstack-aimiddleware-mcp-grafana + restart: "no" + environment: + - GRAFANA_URL=${GRAFANA_URL} + - GRAFANA_TOKEN=${GRAFANA_TOKEN} + profiles: + - ops + + # ========================================== + # Business Intelligence (1 server) + # ========================================== + + # Superset MCP - Apache Superset integration + # NOTE: This is a stdio-based MCP server, run on-demand by Crush via docker run + superset-mcp: + image: kneldevstack-aimiddleware-superset-mcp + build: + context: ./vendor/superset-mcp + dockerfile: ../../dockerfiles/superset-mcp/Dockerfile + container_name: kneldevstack-aimiddleware-superset-mcp + restart: "no" + environment: + - PYTHONUNBUFFERED=1 + - SUPERSET_URL=${SUPERSET_URL} + - SUPERSET_USERNAME=${SUPERSET_USERNAME} + - SUPERSET_PASSWORD=${SUPERSET_PASSWORD} + profiles: + - ops + volumes: ghidra-projects: ghidra-data: diff --git a/dockerfiles/actual-mcp/Dockerfile b/dockerfiles/actual-mcp/Dockerfile new file mode 100644 index 0000000..3d212bf --- /dev/null +++ b/dockerfiles/actual-mcp/Dockerfile @@ -0,0 +1,13 @@ +FROM node:22-alpine + +WORKDIR /app + +COPY package.json package-lock.json* ./ + +RUN npm ci --ignore-scripts + +COPY . . + +RUN npm run build + +CMD ["node", "build/index.js"] diff --git a/dockerfiles/beszel-mcp/Dockerfile b/dockerfiles/beszel-mcp/Dockerfile new file mode 100644 index 0000000..bd4ce64 --- /dev/null +++ b/dockerfiles/beszel-mcp/Dockerfile @@ -0,0 +1,14 @@ +FROM python:3.12-slim + +COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ + +WORKDIR /app + +COPY . . + +RUN uv venv && uv pip install --no-cache -e . + +ENV PYTHONUNBUFFERED=1 +ENV PATH=/app/.venv/bin:$PATH + +ENTRYPOINT ["python", "-m", "beszel_mcp"] diff --git a/dockerfiles/gitea-mcp/Dockerfile b/dockerfiles/gitea-mcp/Dockerfile new file mode 100644 index 0000000..042f474 --- /dev/null +++ b/dockerfiles/gitea-mcp/Dockerfile @@ -0,0 +1,18 @@ +FROM golang:1.24-alpine AS builder + +WORKDIR /app + +COPY go.mod go.sum ./ +RUN go mod download + +COPY . . + +RUN CGO_ENABLED=0 go build -o gitea-mcp . + +FROM alpine:3.20 + +RUN apk --no-cache add ca-certificates + +COPY --from=builder /app/gitea-mcp /usr/local/bin/gitea-mcp + +ENTRYPOINT ["/usr/local/bin/gitea-mcp"] diff --git a/dockerfiles/ha-mcp/Dockerfile b/dockerfiles/ha-mcp/Dockerfile new file mode 100644 index 0000000..ffd2cf9 --- /dev/null +++ b/dockerfiles/ha-mcp/Dockerfile @@ -0,0 +1,14 @@ +FROM python:3.13-slim + +COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ + +WORKDIR /app + +COPY . . + +RUN uv venv && uv pip install --no-cache -e . + +ENV PYTHONUNBUFFERED=1 +ENV PATH=/app/.venv/bin:$PATH + +ENTRYPOINT ["python", "-m", "ha_mcp"] diff --git a/dockerfiles/limesurvey-mcp/Dockerfile b/dockerfiles/limesurvey-mcp/Dockerfile new file mode 100644 index 0000000..a495f89 --- /dev/null +++ b/dockerfiles/limesurvey-mcp/Dockerfile @@ -0,0 +1,13 @@ +FROM node:22-alpine + +WORKDIR /app + +COPY package.json package-lock.json* ./ + +RUN npm ci --ignore-scripts + +COPY . . + +RUN npm run build + +CMD ["node", "dist/index.js"] diff --git a/dockerfiles/linkwarden-mcp/Dockerfile b/dockerfiles/linkwarden-mcp/Dockerfile new file mode 100644 index 0000000..bf08ec4 --- /dev/null +++ b/dockerfiles/linkwarden-mcp/Dockerfile @@ -0,0 +1,18 @@ +FROM golang:1.23-alpine AS builder + +WORKDIR /app + +COPY go.mod go.sum ./ +RUN go mod download + +COPY . . + +RUN CGO_ENABLED=0 go build -o linkwarden-mcp-server ./cmd/linkwarden-mcp-server + +FROM alpine:3.20 + +RUN apk --no-cache add ca-certificates + +COPY --from=builder /app/linkwarden-mcp-server /usr/local/bin/linkwarden-mcp-server + +ENTRYPOINT ["/usr/local/bin/linkwarden-mcp-server", "stdio"] diff --git a/dockerfiles/mcp-grafana/Dockerfile b/dockerfiles/mcp-grafana/Dockerfile new file mode 100644 index 0000000..da1eb3a --- /dev/null +++ b/dockerfiles/mcp-grafana/Dockerfile @@ -0,0 +1,18 @@ +FROM golang:1.24-alpine AS builder + +WORKDIR /app + +COPY go.mod go.sum ./ +RUN go mod download + +COPY . . + +RUN CGO_ENABLED=0 go build -o mcp-grafana ./cmd/mcp-grafana + +FROM alpine:3.20 + +RUN apk --no-cache add ca-certificates + +COPY --from=builder /app/mcp-grafana /usr/local/bin/mcp-grafana + +ENTRYPOINT ["/usr/local/bin/mcp-grafana", "--transport", "stdio"] diff --git a/dockerfiles/superset-mcp/Dockerfile b/dockerfiles/superset-mcp/Dockerfile new file mode 100644 index 0000000..b434bfd --- /dev/null +++ b/dockerfiles/superset-mcp/Dockerfile @@ -0,0 +1,14 @@ +FROM python:3.12-slim + +COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ + +WORKDIR /app + +COPY . . + +RUN uv venv && uv pip install --no-cache -e . + +ENV PYTHONUNBUFFERED=1 +ENV PATH=/app/.venv/bin:$PATH + +ENTRYPOINT ["python", "main.py"] diff --git a/mcp-actual-wrapper.sh b/mcp-actual-wrapper.sh new file mode 100755 index 0000000..6141529 --- /dev/null +++ b/mcp-actual-wrapper.sh @@ -0,0 +1,22 @@ +#!/bin/sh +# Wrapper script for actual-mcp +# Ensures clean container with proper name + +CONTAINER_NAME="kneldevstack-aimiddleware-actual-mcp-crush" +IMAGE_NAME="kneldevstack-aimiddleware-actual-mcp" + +# Force remove existing container if it exists (in any state) +if docker ps -a --filter "name=${CONTAINER_NAME}" --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then + docker rm -f "${CONTAINER_NAME}" 2>/dev/null + # Wait for container to be fully removed + while docker ps -a --filter "name=${CONTAINER_NAME}" --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; do + sleep 0.05 + done +fi + +# Start MCP server with explicit name and environment +exec docker run -i --rm --name "${CONTAINER_NAME}" \ + -e ACTUAL_SERVER_URL="${ACTUAL_SERVER_URL}" \ + -e ACTUAL_PASSWORD="${ACTUAL_PASSWORD}" \ + -e ACTUAL_BUDGET_SYNC_ID="${ACTUAL_BUDGET_SYNC_ID}" \ + "${IMAGE_NAME}" "$@" diff --git a/mcp-beszel-wrapper.sh b/mcp-beszel-wrapper.sh new file mode 100755 index 0000000..23bfeb1 --- /dev/null +++ b/mcp-beszel-wrapper.sh @@ -0,0 +1,22 @@ +#!/bin/sh +# Wrapper script for beszel-mcp +# Ensures clean container with proper name + +CONTAINER_NAME="kneldevstack-aimiddleware-beszel-mcp-crush" +IMAGE_NAME="kneldevstack-aimiddleware-beszel-mcp" + +# Force remove existing container if it exists (in any state) +if docker ps -a --filter "name=${CONTAINER_NAME}" --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then + docker rm -f "${CONTAINER_NAME}" 2>/dev/null + # Wait for container to be fully removed + while docker ps -a --filter "name=${CONTAINER_NAME}" --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; do + sleep 0.05 + done +fi + +# Start MCP server with explicit name and environment +exec docker run -i --rm --name "${CONTAINER_NAME}" \ + -e BESZEL_URL="${BESZEL_URL}" \ + -e BESZEL_USERNAME="${BESZEL_USERNAME}" \ + -e BESZEL_PASSWORD="${BESZEL_PASSWORD}" \ + "${IMAGE_NAME}" "$@" diff --git a/mcp-gitea-wrapper.sh b/mcp-gitea-wrapper.sh new file mode 100755 index 0000000..5490329 --- /dev/null +++ b/mcp-gitea-wrapper.sh @@ -0,0 +1,21 @@ +#!/bin/sh +# Wrapper script for gitea-mcp +# Ensures clean container with proper name + +CONTAINER_NAME="kneldevstack-aimiddleware-gitea-mcp-crush" +IMAGE_NAME="kneldevstack-aimiddleware-gitea-mcp" + +# Force remove existing container if it exists (in any state) +if docker ps -a --filter "name=${CONTAINER_NAME}" --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then + docker rm -f "${CONTAINER_NAME}" 2>/dev/null + # Wait for container to be fully removed + while docker ps -a --filter "name=${CONTAINER_NAME}" --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; do + sleep 0.05 + done +fi + +# Start MCP server with explicit name and environment +exec docker run -i --rm --name "${CONTAINER_NAME}" \ + -e GITEA_URL="${GITEA_URL}" \ + -e GITEA_TOKEN="${GITEA_TOKEN}" \ + "${IMAGE_NAME}" "$@" diff --git a/mcp-grafana-wrapper.sh b/mcp-grafana-wrapper.sh new file mode 100755 index 0000000..73fc0d4 --- /dev/null +++ b/mcp-grafana-wrapper.sh @@ -0,0 +1,21 @@ +#!/bin/sh +# Wrapper script for mcp-grafana +# Ensures clean container with proper name + +CONTAINER_NAME="kneldevstack-aimiddleware-mcp-grafana-crush" +IMAGE_NAME="kneldevstack-aimiddleware-mcp-grafana" + +# Force remove existing container if it exists (in any state) +if docker ps -a --filter "name=${CONTAINER_NAME}" --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then + docker rm -f "${CONTAINER_NAME}" 2>/dev/null + # Wait for container to be fully removed + while docker ps -a --filter "name=${CONTAINER_NAME}" --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; do + sleep 0.05 + done +fi + +# Start MCP server with explicit name and environment +exec docker run -i --rm --name "${CONTAINER_NAME}" \ + -e GRAFANA_URL="${GRAFANA_URL}" \ + -e GRAFANA_TOKEN="${GRAFANA_TOKEN}" \ + "${IMAGE_NAME}" "$@" diff --git a/mcp-ha-wrapper.sh b/mcp-ha-wrapper.sh new file mode 100755 index 0000000..f2616b8 --- /dev/null +++ b/mcp-ha-wrapper.sh @@ -0,0 +1,21 @@ +#!/bin/sh +# Wrapper script for ha-mcp (Home Assistant) +# Ensures clean container with proper name + +CONTAINER_NAME="kneldevstack-aimiddleware-ha-mcp-crush" +IMAGE_NAME="kneldevstack-aimiddleware-ha-mcp" + +# Force remove existing container if it exists (in any state) +if docker ps -a --filter "name=${CONTAINER_NAME}" --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then + docker rm -f "${CONTAINER_NAME}" 2>/dev/null + # Wait for container to be fully removed + while docker ps -a --filter "name=${CONTAINER_NAME}" --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; do + sleep 0.05 + done +fi + +# Start MCP server with explicit name and environment +exec docker run -i --rm --name "${CONTAINER_NAME}" \ + -e HOMEASSISTANT_URL="${HOMEASSISTANT_URL}" \ + -e HOMEASSISTANT_TOKEN="${HOMEASSISTANT_TOKEN}" \ + "${IMAGE_NAME}" "$@" diff --git a/mcp-limesurvey-wrapper.sh b/mcp-limesurvey-wrapper.sh new file mode 100755 index 0000000..12f7e2c --- /dev/null +++ b/mcp-limesurvey-wrapper.sh @@ -0,0 +1,22 @@ +#!/bin/sh +# Wrapper script for limesurvey-mcp +# Ensures clean container with proper name + +CONTAINER_NAME="kneldevstack-aimiddleware-limesurvey-mcp-crush" +IMAGE_NAME="kneldevstack-aimiddleware-limesurvey-mcp" + +# Force remove existing container if it exists (in any state) +if docker ps -a --filter "name=${CONTAINER_NAME}" --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then + docker rm -f "${CONTAINER_NAME}" 2>/dev/null + # Wait for container to be fully removed + while docker ps -a --filter "name=${CONTAINER_NAME}" --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; do + sleep 0.05 + done +fi + +# Start MCP server with explicit name and environment +exec docker run -i --rm --name "${CONTAINER_NAME}" \ + -e LIMESURVEY_URL="${LIMESURVEY_URL}" \ + -e LIMESURVEY_USERNAME="${LIMESURVEY_USERNAME}" \ + -e LIMESURVEY_PASSWORD="${LIMESURVEY_PASSWORD}" \ + "${IMAGE_NAME}" "$@" diff --git a/mcp-linkwarden-wrapper.sh b/mcp-linkwarden-wrapper.sh new file mode 100755 index 0000000..c853592 --- /dev/null +++ b/mcp-linkwarden-wrapper.sh @@ -0,0 +1,21 @@ +#!/bin/sh +# Wrapper script for linkwarden-mcp +# Ensures clean container with proper name + +CONTAINER_NAME="kneldevstack-aimiddleware-linkwarden-mcp-crush" +IMAGE_NAME="kneldevstack-aimiddleware-linkwarden-mcp" + +# Force remove existing container if it exists (in any state) +if docker ps -a --filter "name=${CONTAINER_NAME}" --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then + docker rm -f "${CONTAINER_NAME}" 2>/dev/null + # Wait for container to be fully removed + while docker ps -a --filter "name=${CONTAINER_NAME}" --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; do + sleep 0.05 + done +fi + +# Start MCP server with explicit name and environment +exec docker run -i --rm --name "${CONTAINER_NAME}" \ + -e LINKWARDEN_URL="${LINKWARDEN_URL}" \ + -e LINKWARDEN_TOKEN="${LINKWARDEN_TOKEN}" \ + "${IMAGE_NAME}" "$@" diff --git a/mcp-superset-wrapper.sh b/mcp-superset-wrapper.sh new file mode 100755 index 0000000..aee780d --- /dev/null +++ b/mcp-superset-wrapper.sh @@ -0,0 +1,22 @@ +#!/bin/sh +# Wrapper script for superset-mcp +# Ensures clean container with proper name + +CONTAINER_NAME="kneldevstack-aimiddleware-superset-mcp-crush" +IMAGE_NAME="kneldevstack-aimiddleware-superset-mcp" + +# Force remove existing container if it exists (in any state) +if docker ps -a --filter "name=${CONTAINER_NAME}" --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then + docker rm -f "${CONTAINER_NAME}" 2>/dev/null + # Wait for container to be fully removed + while docker ps -a --filter "name=${CONTAINER_NAME}" --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; do + sleep 0.05 + done +fi + +# Start MCP server with explicit name and environment +exec docker run -i --rm --name "${CONTAINER_NAME}" \ + -e SUPERSET_URL="${SUPERSET_URL}" \ + -e SUPERSET_USERNAME="${SUPERSET_USERNAME}" \ + -e SUPERSET_PASSWORD="${SUPERSET_PASSWORD}" \ + "${IMAGE_NAME}" "$@"