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
6 changes: 5 additions & 1 deletion .github/image/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
FROM debian:12-slim

RUN apt-get update && apt-get install -y ca-certificates build-essential libssl-dev pkg-config && rm -rf /var/lib/apt/lists/*
RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates curl \
&& curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash \
&& apt-get purge -y --auto-remove curl \
&& rm -rf /var/lib/apt/lists/*

ARG TARGETARCH
ARG BIN
Expand Down
108 changes: 108 additions & 0 deletions .github/workflows/build_mcp_server.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
name: Build MCP server

on:
push:
branches:
- "main"
paths:
- ".github/image/Dockerfile"
- ".github/workflows/build_mcp_server.yml"
- "mcp-server/**"

jobs:
build:
continue-on-error: true

strategy:
matrix:
include:
- release_for: Linux-x86_64
build_on: ubuntu-22.04
target: x86_64-unknown-linux-gnu
args: "--locked --release"

- release_for: Linux-arm64
build_on: ubuntu-22.04-arm
target: "aarch64-unknown-linux-gnu"
args: "--locked --release"
Comment on lines +18 to +27

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Add missing ext property to matrix entries.

Lines 50-51 and 57 reference matrix.ext, but the matrix entries do not define this property, causing a workflow syntax error.

🐛 Proposed fix
         include:
           - release_for: Linux-x86_64
             build_on: ubuntu-22.04
             target: x86_64-unknown-linux-gnu
             args: "--locked --release"
+            ext: ""

           - release_for: Linux-arm64
             build_on: ubuntu-22.04-arm
             target: "aarch64-unknown-linux-gnu"
             args: "--locked --release"
+            ext: ""
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
include:
- release_for: Linux-x86_64
build_on: ubuntu-22.04
target: x86_64-unknown-linux-gnu
args: "--locked --release"
- release_for: Linux-arm64
build_on: ubuntu-22.04-arm
target: "aarch64-unknown-linux-gnu"
args: "--locked --release"
include:
- release_for: Linux-x86_64
build_on: ubuntu-22.04
target: x86_64-unknown-linux-gnu
args: "--locked --release"
ext: ""
- release_for: Linux-arm64
build_on: ubuntu-22.04-arm
target: "aarch64-unknown-linux-gnu"
args: "--locked --release"
ext: ""
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/build_mcp_server.yml around lines 18 - 27, The matrix
entries under include (the objects with keys release_for, build_on, target,
args) are missing the ext property referenced elsewhere as matrix.ext; add an
ext field to each included matrix entry (e.g., add ext: "<appropriate
extension>" to the Linux-x86_64 and Linux-arm64 include objects) so matrix.ext
resolves correctly where used on lines referencing matrix.ext.


runs-on: ${{ matrix.build_on }}

steps:
- name: checkout repository
uses: actions/checkout@v4

- uses: Swatinem/rust-cache@v2
with:
shared-key: "release"
workspaces: mcp-server -> target

- name: Install stable toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: stable

- name: Run cargo build
run: cargo build --target ${{ matrix.target }} ${{ matrix.args }}
working-directory: mcp-server

- name: rename binaries
run: |
mv target/${{ matrix.target }}/release/supernode-mcp${{ matrix.ext }} supernode-mcp-${{ matrix.release_for }}${{ matrix.ext }}

- name: upload
uses: actions/upload-artifact@v4
with:
name: binaries-supernode-mcp-${{ matrix.release_for }}
path: supernode-mcp-${{ matrix.release_for }}${{ matrix.ext }}

docker:
runs-on: ubuntu-latest
needs: [build]

strategy:
matrix:
include:
- tags: ghcr.io/txpipe/metis-supernode-mcp,ghcr.io/txpipe/metis-supernode-mcp:${{ github.sha }}
binary: supernode-mcp

Comment on lines +63 to +68

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Move dynamic tag generation out of the matrix definition.

GitHub Actions does not interpolate expressions like ${{ github.sha }} inside matrix definitions. The SHA tag will be literal text, not the actual commit SHA.

🔧 Proposed fix

Move tag generation to a step that sets an output or environment variable, then reference it in the build step:

     strategy:
       matrix:
         include:
-          - tags: ghcr.io/txpipe/metis-supernode-mcp,ghcr.io/txpipe/metis-supernode-mcp:${{ github.sha }}
-            binary: supernode-mcp
+          - binary: supernode-mcp

     permissions:
       contents: read
       packages: write

     steps:
       - name: Checkout repository
         uses: actions/checkout@v4
+
+      - name: Prepare tags
+        id: tags
+        run: |
+          echo "tags=ghcr.io/txpipe/metis-supernode-mcp,ghcr.io/txpipe/metis-supernode-mcp:${{ github.sha }}" >> $GITHUB_OUTPUT

       - name: Set up Docker Buildx
         uses: docker/setup-buildx-action@v3

Then update line 107:

-          tags: ${{ matrix.tags }}
+          tags: ${{ steps.tags.outputs.tags }}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/build_mcp_server.yml around lines 63 - 68, The matrix
currently hardcodes tags including the expression `${{ github.sha }}` which
won’t be interpolated; move dynamic tag generation out of the matrix by
replacing the matrix "tags" entry with a static placeholder (or remove the
SHA-specific tag) and add a prior step that computes the tags string using `${{
github.sha }}` and exposes it as an output or env var (e.g., set-output/tag or
echo to GITHUB_ENV). Then update the build/publish step that uses the matrix
`tags` (the step that references `tags`/`binary`) to instead consume the
computed output/env variable so the actual commit SHA is included in the runtime
tag list.

permissions:
contents: read
packages: write

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Login to DockerHub
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Download artifacts
uses: actions/download-artifact@v4
with:
pattern: binaries-*
merge-multiple: true
path: .github/image/bin

- uses: satackey/action-docker-layer-caching@v0.0.11
continue-on-error: true

- name: Rename artifacts
run: |+
mv .github/image/bin/supernode-mcp-Linux-x86_64 .github/image/bin/supernode-mcp-Linux-amd64

- name: Build and push
uses: docker/build-push-action@v5
with:
context: .github/image
platforms: linux/arm64,linux/amd64
push: true
tags: ${{ matrix.tags }}
build-args: BIN=${{ matrix.binary }}
28 changes: 28 additions & 0 deletions .github/workflows/check_mcp_server.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Check MCP server

on:
push:
branches:
- main
paths:
- ".github/workflows/check_mcp_server.yml"
- "mcp-server/**"
pull_request:
branches:
- main
paths:
- ".github/workflows/check_mcp_server.yml"
- "mcp-server/**"

jobs:
lint:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./mcp-server
steps:
- name: Checkout
uses: actions/checkout@v3

- name: Clippy check lints
run: cargo clippy -- -D warnings
28 changes: 28 additions & 0 deletions .github/workflows/test_mcp_server.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Test MCP server

on:
push:
branches:
- main
paths:
- ".github/workflows/test_mcp_server.yml"
- "mcp-server/**"
pull_request:
branches:
- main
paths:
- ".github/workflows/test_mcp_server.yml"
- "mcp-server/**"

jobs:
lint:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./mcp-server
steps:
- name: Checkout
uses: actions/checkout@v3

- name: Test
run: cargo test
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
/cli/target
/backend/target
/operator/target
/mcp-server/target

.env
cert
Expand Down
65 changes: 65 additions & 0 deletions bootstrap/kind/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,71 @@ If you want to configure the shared VSO auth resources after the install, use:
VAULT_TOKEN=root ../extensions/control-plane/scripts/post_install.sh
```

## Local Control Plane With Local MCP Image

Use this flow when testing local MCP server changes in Kind before publishing an
image.

Create or reuse the Kind cluster:

```bash
./bootstrap/kind/bootstrap.sh --config ./bootstrap/kind/config.yml
```

Build and load the local MCP image into Kind:

```bash
docker build -t metis-supernode-mcp:dev ./mcp-server
kind load docker-image metis-supernode-mcp:dev --name "${KIND_CLUSTER_NAME:-supernode}"
```

Install the local control-plane chart with the local MCP image and dev Vault:

```bash
helm dependency build ./extensions/control-plane
helm upgrade --install control-plane ./extensions/control-plane \
--namespace control-plane \
--create-namespace \
--values ./bootstrap/kind/values.yml \
--values ./extensions/control-plane/examples/dev-values.yaml \
--set supernodeMcp.image.repository=metis-supernode-mcp \
--set supernodeMcp.image.tag=dev \
--set supernodeMcp.image.pullPolicy=Never
```

The control-plane chart enables a PVC-backed SQLite MCP session store by
default. This lets existing MCP sessions survive a pod restart, as long as the
client keeps using the same `Mcp-Session-Id` and the session has not expired.

Configure Vault for local MCP runtime-secret operations:

```bash
VAULT_TOKEN=root ./extensions/control-plane/scripts/post_install.sh
```

Forward the MCP service and check health:

```bash
kubectl -n control-plane rollout status deployment/supernode-mcp
kubectl -n control-plane port-forward service/supernode-mcp 8082:8443
curl http://127.0.0.1:8082/healthz
```

Live `workloads.install` calls are enabled through MCP. Use `dryRun: true` to
inspect the generated Helm values, then call the same tool with `dryRun: false`
to apply the install.

When rebuilding the MCP image, load it again and restart the deployment:

```bash
docker build -t metis-supernode-mcp:dev ./mcp-server
kind load docker-image metis-supernode-mcp:dev --name "${KIND_CLUSTER_NAME:-supernode}"
kubectl -n control-plane rollout restart deployment/supernode-mcp
```

MCP clients should reinitialize only when the server returns `404 Session not
found`, which means the session was deleted, expired, or the PVC was replaced.

## Outputs

- Creates (or reuses) a Kind cluster named `supernode` by default.
Expand Down
1 change: 1 addition & 0 deletions extensions/cardano-node/templates/configmap-metrics.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,7 @@ data:
(if $kesExpirationSecondsValue != null then $kesExpirationSecondsValue elif $kesRemainingValue != null and $slotsPerKESPeriodValue != null and $slotLengthValue != null then (($kesRemainingValue * $slotsPerKESPeriodValue * $slotLengthValue) | floor) else null end) as $resolvedKesExpirationSeconds |
{
type: "cardano-node",
role: "relay",
blockHeight: nullable_number($blockHeight),
epoch: nullable_number($epoch),
slotNum: $slotNumValue,
Expand Down
18 changes: 15 additions & 3 deletions extensions/control-plane/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,10 @@ For dev mode, skip initialization and unseal entirely.
requires the `vault` CLI to be installed on your machine, assumes
`vault operator init` has already been run for standalone or HA modes,
port-forwards to `service/control-plane-vault`, and configures the shared
Kubernetes auth mount, KV v2 mount, policy, and role using the local
`vault` CLI. By default, the shared role can read only `kv/runtime/...`.
Kubernetes auth mount, KV v2 mount, shared workload policy/role, and MCP
Vault token Secret using the local `vault` CLI. By default, the shared role
can read only `kv/runtime/...`, while the MCP token can read/write only
`kv/runtime/...`.

```shell
VAULT_TOKEN=<vault-admin-token> ./scripts/post_install.sh
Expand All @@ -189,7 +191,8 @@ kubectl -n control-plane exec -it control-plane-vault-0 -- \
```

The `post_install.sh` script is safe to rerun when you intentionally want to
reconcile the Vault auth mount, policy, role, or KV mount.
reconcile the Vault auth mount, policy, role, KV mount, or MCP Vault token
Secret.

The default post-install policy is intentionally read-only and prefix-scoped.
Workload charts that create `VaultStaticSecret` resources are expected to
Expand Down Expand Up @@ -346,6 +349,15 @@ helm template control-plane . -f examples/aws-values.yaml | kubeconform -strict
| `prometheusOperator.tolerations` | Tolerations applied to the Prometheus Operator deployment | `[]` |
| `grafana.tolerations` | Tolerations applied to the Grafana StatefulSet | `[]` |
| `prometheus.tolerations` | Tolerations applied to the Prometheus CRD | `[]` |
| `supernodeMcp.sessionStore.type` | MCP Streamable HTTP session store (`sqlite` or `memory`) | `sqlite` |
| `supernodeMcp.sessionStore.sqlitePath` | SQLite database path for restart-resistant MCP sessions | `/var/lib/supernode-mcp/sessions.sqlite3` |
| `supernodeMcp.sessionStore.ttlSeconds` | Session restore TTL in seconds | `86400` |
| `supernodeMcp.helm.valuesDir` | Writable directory used for generated MCP Helm values files | `/var/lib/supernode-mcp/helm/values` |
| `supernodeMcp.helm.cacheHome` | Helm cache directory for the MCP container | `/var/lib/supernode-mcp/helm/cache` |
| `supernodeMcp.helm.configHome` | Helm config directory for the MCP container | `/var/lib/supernode-mcp/helm/config` |
| `supernodeMcp.helm.dataHome` | Helm data directory for the MCP container | `/var/lib/supernode-mcp/helm/data` |
| `supernodeMcp.persistence.enabled` | Creates a PVC for the MCP SQLite session store | `true` |
| `supernodeMcp.persistence.size` | MCP session store PVC size | `1Gi` |

Consult `values.yaml` for the authoritative list.

Expand Down
Loading
Loading