Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,36 @@ jobs:
--set image.tag="${{ github.sha }}" \
$values

reconcile:
needs: detect
# Removing a toolset always touches shared paths (uv.lock, root
# pyproject.toml), so any removal lands in a run with a non-empty matrix;
# docs-only pushes skip, keeping kubeconfig out of no-op runs.
if: needs.detect.outputs.toolsets != '[]'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Configure kubeconfig
run: |
mkdir -p ~/.kube
printf '%s' "${KUBE_CONFIG}" > ~/.kube/config
chmod 600 ~/.kube/config
env:
KUBE_CONFIG: ${{ secrets.KUBE_CONFIG }}
- name: Uninstall releases whose toolset directory is gone
run: |
for release in $(helm list --namespace mcp-toolsets --short); do
case "$release" in
mcp-index) continue ;;
mcp-*) toolset="${release#mcp-}" ;;
*) continue ;;
esac
if [ ! -d "toolsets/$toolset" ]; then
echo "Uninstalling $release: toolsets/$toolset no longer exists"
helm uninstall "$release" --namespace mcp-toolsets
fi
done

index:
needs: detect
# Skip no-op pushes (e.g. docs): the index image is built from shared code,
Expand Down
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,22 @@ tools and merge.
Conventions: directory `toolsets/<name>` (kebab-case) → module
`<name_snake_case>.tools` → service `mcp-<name>`.

## Removing a toolset

```sh
./scripts/remove-toolset my-toolset
```

Merge to `main`. Removal is GitOps like everything else: the deploy
workflow reconciles the cluster against `toolsets/`, uninstalling any
`mcp-<name>` release whose directory no longer exists — Deployment, Service
and Ingress with it; the index drops the entry automatically. Mind that
this means merging a deleted directory tears down the live service.

Not removed automatically: out-of-band Secrets the toolset listed in its
`toolset.yaml` (`kubectl -n mcp-toolsets delete secret <name>`) and its
images in GHCR (delete the package from the repo settings if you care).

## Deployment

- **ci.yml** (PRs + main): lint, tests, `helm lint`, and a no-push Docker
Expand All @@ -102,6 +118,8 @@ Conventions: directory `toolsets/<name>` (kebab-case) → module
root `pyproject.toml`) rebuild *all* toolsets — then per toolset: build and
push `ghcr.io/<owner>/<repo>/mcp-<name>:<sha>` and
`helm upgrade --install mcp-<name> charts/mcp-toolset -n mcp-toolsets`.
A reconcile job also uninstalls releases whose `toolsets/<name>` directory
is gone — see [Removing a toolset](#removing-a-toolset).
- **Required secret**: `KUBE_CONFIG` — a kubeconfig with rights to manage the
`mcp-toolsets` namespace. Images push to GHCR with the built-in
`GITHUB_TOKEN`.
Expand Down
31 changes: 31 additions & 0 deletions scripts/remove-toolset
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#!/usr/bin/env sh
# Remove a toolset: scripts/remove-toolset <name>
#
# Deletes toolsets/<name> and deregisters it from the uv workspace. Merging
# the removal to main uninstalls the deployed mcp-<name> release: the deploy
# workflow reconciles the cluster against the toolsets/ directory.

set -e

name="$1"
if [ -z "$name" ]; then
echo "usage: scripts/remove-toolset <name>" >&2
exit 1
fi
dir="toolsets/$name"
if [ ! -d "$dir" ]; then
echo "error: $dir does not exist" >&2
exit 1
fi

uv remove "$name"
rm -rf "$dir"
# Re-lock: the removal above ran while the directory still existed, so the
# lockfile still listed it as a workspace member.
uv sync

echo
echo "Removed $dir and deregistered it from the workspace."
echo "Merge to main: the deploy workflow uninstalls the mcp-$name release."
echo "Not removed automatically: out-of-band Secrets the toolset listed in"
echo "toolset.yaml, and its images in GHCR."
Loading