Compare commits

...
87 Commits
Author SHA1 Message Date
olb042 78b1119710 Fix full VMCP redirect URI 2026-06-23 19:15:35 +01:00
olb042 48476c7dac Fix full VMCP audience 2026-06-23 19:12:19 +01:00
olb042 d393f66d47 add back ingress 2026-06-17 17:37:24 +01:00
olb042 de8f55c253 move to public-mcp 2026-06-17 17:25:52 +01:00
olb042 a72a2055af move to public-mcp 2026-06-17 16:48:38 +01:00
olb042 676bad4dd2 Implement shared public MCP federation gateway
- full-vmcp serves as public entry point at mcp.ngorse.com
- Single Keycloak client (public-mcp) for all external tools
- authServerConfig proxies auth to Keycloak
- state-docs-vmcp becomes internal-only (no auth required)
- Shared OIDC config for token validation
- All external clients authenticate once at gateway
2026-06-17 16:26:48 +01:00
olb042 d1d8c6aa3f change audidence 2026-06-17 15:35:15 +01:00
olb042 a7f069bdd7 add ngorse ingress 2026-06-17 15:28:57 +01:00
olb042 95fcbb5441 seperate ingress 2026-06-17 15:27:40 +01:00
olb042 841bb8e6c8 Simplify authServerConfig to only required CRD fields 2026-06-17 15:02:35 +01:00
olb042 d402c1726e test toolhive.stacklok.dev/v1beta1 2026-06-17 14:59:12 +01:00
olb042 919888aba6 test toolhive.stacklok.dev/v1beta1 2026-06-17 14:57:49 +01:00
olb042 b6f6c3ebe4 Configure OIDC auth servers for VMCP servers to proxy through Keycloak 2026-06-17 14:52:02 +01:00
olb042 4de136186f change auth for vmcp 2026-06-17 14:49:54 +01:00
olb042andClaude Sonnet 4.6 ad0e5df277 fix: add required audience field to oidcConfigRef on both VirtualMCPServers
spec.incomingAuth.oidcConfigRef.audience is Required by the CRD validator.
Set to the Keycloak client ID for each server (unique per server as required
to prevent token replay attacks).

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-06-15 13:34:33 +00:00
olb042andClaude Sonnet 4.6 3caeeb2997 fix: replace invalid incomingAuth.oidc with MCPOIDCConfig + oidcConfigRef
The .spec.incomingAuth.oidc inline block is not a valid field in the
v0.29.3 VirtualMCPServer CRD schema, causing ArgoCD ComparisonErrors.

The correct v0.29.3 API separates OIDC provider config into a dedicated
MCPOIDCConfig (v1beta1) resource, referenced from the VirtualMCPServer
via spec.incomingAuth.oidcConfigRef.name.

- Add MCPOIDCConfig resources for state-docs-vmcp and full-vmcp (inline
  type, Keycloak issuer, replicated client secrets from keycloak ns)
- Update state-docs-vmcp and full-vmcp VirtualMCPServer manifests to
  reference the new MCPOIDCConfig resources via oidcConfigRef
- Register new MCPOIDCConfig files in vmcp-servers kustomization

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-06-15 13:31:45 +00:00
olb042andClaude Sonnet 4.6 d09eb39701 narrow ignoreApplicationDifferences to /automated/enabled only
Previously ignoring the entire /spec/syncPolicy prevented the ApplicationSet
controller from propagating syncOption changes (like ServerSideDiff=true) to
the live Application. Now only /automated/enabled is ignored, preserving
manual auto-sync control while allowing syncOptions to reconcile normally.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-06-15 13:04:59 +00:00
olb042andClaude Sonnet 4.6 50fdec56cb add ServerSideDiff=true to bypass incomingAuth.oidc schema error
ArgoCD's client-side structured merge diff fails on VirtualMCPServer
resources that use spec.incomingAuth.oidc because the CRD schema does
not declare that subfield. ServerSideDiff=true switches diff computation
to a server-side dry-run which handles preserved-unknown-fields correctly.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-06-15 13:03:54 +00:00
olb042 457d042569 add vmcp 2026-06-15 13:54:03 +01:00
olb042andClaude Sonnet 4.6 f82d0b449b remove stale TODO for state-docs-vmcp sealed secret
Secret is replicated from Keycloak into toolhive-system; no sealed secret needed.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-06-15 12:10:25 +00:00
olb042 9f162958bf oidc auth 2026-06-15 12:59:34 +01:00
olb042 f74bf9e50f temp oidc auth 2026-06-15 12:58:50 +01:00
olb042 adc06573cc update version 2026-06-15 12:49:25 +01:00
olb042andClaude Sonnet 4.6 b497211278 add OIDC auth to state-docs-vmcp VirtualMCPServer
Switch incomingAuth from anonymous to oidc, wiring Keycloak (home-lab realm
at cloak.olb42.com) as the provider with clientId state-docs-vmcp. Secret
ref (state-docs-vmcp-secret, key: client-secret) is added to kustomization
as a TODO comment pending the sealed secret creation.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-06-14 16:55:43 +00:00
olb042 8b9e54a924 update ingress 2026-06-14 02:40:20 +01:00
olb042 4da61242df update ssl 2026-06-14 02:29:04 +01:00
olb042 6ff5eaafa2 add second ingressroute 2026-06-14 02:11:42 +01:00
olb042 6da4451697 add internal dns 2026-06-14 02:05:02 +01:00
olb042 b58c369d11 embedding 2026-06-13 20:47:48 +01:00
olb042 cc1bb128e1 enable tools 2026-06-13 20:45:37 +01:00
olb042 62b1214926 add incoming auth 2026-06-13 20:19:53 +01:00
olb042 ab95db2782 add state doc 2026-06-13 20:16:18 +01:00
olb042 ccd0093f00 add state docs 2026-06-13 20:09:43 +01:00
olb042 3e78b15f19 add registry visible remote mcp proxies 2026-06-13 19:59:04 +01:00
olb042 13d58831b4 fix registry discovery rbac for mcp entries 2026-06-13 19:55:57 +01:00
olb042 bf86461753 argocd and kube mcp to read-write 2026-06-13 19:33:23 +01:00
olb042 5a1f1f352b pangolin ingress 2026-06-13 19:29:32 +01:00
olb042 596c464754 glance reg 2026-06-06 00:21:16 +01:00
olb042 5106b5e73c vmcp glance 2026-06-06 00:16:30 +01:00
olb042 6a8328ec88 radar 2026-06-06 00:13:34 +01:00
olb042 d9dda8fef8 pod glance 2026-06-05 23:57:31 +01:00
olb042 6a15fbe49f argocd mcp podtemplate/metadata/annotations/glances.parent 2026-06-05 23:56:49 +01:00
olb042 1bbb463bfe glances changes 2026-06-05 16:25:10 +01:00
olb042 0df4a6b461 glance for gitea mcp 2026-06-05 15:49:20 +01:00
olb042 353ba6a250 change resourceoverides 2026-06-04 23:46:16 +01:00
olb042 7aa4ae4dd6 icon mcp 2026-06-04 20:35:09 +01:00
olb042 a9f3cf86d2 icon fix 2026-06-04 20:33:17 +01:00
olb042 37695d8f40 glances 2026-06-04 19:21:53 +01:00
olb042 cae8eabac1 update services and rbac 2026-06-03 18:09:23 +01:00
olb042 0a03987dae sort into folders 2026-06-03 14:09:28 +01:00
olb042 bf39a87964 add radar mcp 2026-06-03 12:17:23 +01:00
olb042 27e596eaf5 add registry ingress 2026-06-02 21:16:35 +01:00
olb042 b4820326db registry 2026-06-02 20:59:26 +01:00
olb042 fb5c4ab51f update registry 2026-06-02 20:12:32 +01:00
olb042 8c401195d2 add backup 2026-06-02 20:01:34 +01:00
olb042 b5fbd69ed3 add second instance of db 2026-06-02 19:58:35 +01:00
olb042 549fcbd383 single instance 2026-06-02 18:39:20 +01:00
olb042 286a57545b new pg 2026-06-02 18:19:46 +01:00
olb042 ec4b95e79b enable plugin 2026-06-02 18:01:08 +01:00
olb042 81c57f994e toggle 2026-06-02 17:59:44 +01:00
olb042 d64d1cecd6 postgres 2026-06-02 17:48:21 +01:00
olb042 9a6b001034 registry 2026-06-02 17:39:43 +01:00
olb042 18317cc322 registry 2026-06-02 17:38:44 +01:00
olb042 b86719a9d4 add external 2026-06-01 17:02:10 +01:00
olb042 57ae283e6d public-dns 2026-06-01 16:59:01 +01:00
olb042 3f8969bdc3 public dns 2026-06-01 16:56:46 +01:00
olb042 3c90d4d4d2 Fix argocd MCP server transport 2026-06-01 15:40:35 +01:00
olb042 760acb67dd remove https ARGOCD_BASE_URL 2026-06-01 14:54:45 +01:00
olb042 1f4bb15cdc group add argocd 2026-06-01 14:46:50 +01:00
olb042 a63b9ca3d1 add groupref 2026-06-01 14:44:35 +01:00
olb042 339088c163 remove publiuc 2026-06-01 14:27:56 +01:00
olb042 d901b4a99b add external 2026-06-01 14:25:25 +01:00
olb042 58b1e247f2 add additional ingress-routes 2026-06-01 14:12:51 +01:00
olb042 4f4635ac66 change sealed-secret 2026-06-01 13:11:47 +01:00
olb042 8e0b3306f7 ingress change hostname wrong 2026-06-01 12:00:16 +01:00
olb042 441b0d25d3 change-ingress 2026-06-01 11:58:41 +01:00
olb042 b33796c7cf ingress add 2026-06-01 11:49:22 +01:00
olb042 a032a8be92 ingress-vmcp 2026-06-01 11:48:36 +01:00
olb042 873271e673 fix kubernetes 2026-06-01 11:36:22 +01:00
olb042 29dd8e372c vmcp 2026-06-01 11:16:54 +01:00
olb042 e87849d4c3 add vmcp servers 2026-06-01 11:14:44 +01:00
olb042 2e82c3f40b add embedding 2026-06-01 11:03:20 +01:00
olb042 42b7851516 headless services 2026-05-31 22:28:11 +01:00
olb042 b2aed7c42c add groupRef 2026-05-31 19:34:19 +01:00
olb042 dfafe51659 update to toolsOverride 2026-05-31 19:19:58 +01:00
olb042 9ead9d4aee update to toolsFilter 2026-05-31 19:18:26 +01:00
olb042 c7e66a9033 update to beta1 for operator config 2026-05-31 19:16:51 +01:00
40 changed files with 881 additions and 135 deletions
+7 -1
View File
@@ -4,6 +4,9 @@ metadata:
name: toolhive name: toolhive
namespace: argocd namespace: argocd
spec: spec:
ignoreApplicationDifferences:
- jsonPointers:
- /spec/syncPolicy/automated/enabled
goTemplate: true goTemplate: true
goTemplateOptions: ["missingkey=error"] goTemplateOptions: ["missingkey=error"]
generators: generators:
@@ -12,7 +15,7 @@ spec:
- environment: production - environment: production
namespace: toolhive-system namespace: toolhive-system
overlay: production overlay: production
chartVersion: 0.28.3 chartVersion: 0.29.3
template: template:
metadata: metadata:
name: 'toolhive-{{ .environment }}' name: 'toolhive-{{ .environment }}'
@@ -57,3 +60,6 @@ spec:
- CreateNamespace=true - CreateNamespace=true
# CRD schemas are large; SSA avoids the last-applied-config annotation limit. # CRD schemas are large; SSA avoids the last-applied-config annotation limit.
- ServerSideApply=true - ServerSideApply=true
# Use server-side dry-run for diff computation to bypass CRD schema
# validation errors on fields marked x-kubernetes-preserve-unknown-fields.
- ServerSideDiff=true
@@ -0,0 +1,6 @@
apiVersion: toolhive.stacklok.dev/v1alpha1
kind: EmbeddingServer
metadata:
name: homelab-embedding
namespace: toolhive-system
spec: {}
@@ -40,6 +40,12 @@ spec:
- name: mcp-kubernetes-mcp-proxy - name: mcp-kubernetes-mcp-proxy
namespace: toolhive-system namespace: toolhive-system
port: 8080 port: 8080
- kind: Rule
match: Host(`thv-registry.olb42.com`)
services:
- name: k8s-registry-api
namespace: toolhive-system
port: 8080
# No default TLSStore in this cluster, so reference the wildcard cert # No default TLSStore in this cluster, so reference the wildcard cert
# explicitly. olb42-wildcard-tls is auto-reflected into every namespace. # explicitly. olb42-wildcard-tls is auto-reflected into every namespace.
tls: tls:
@@ -5,14 +5,15 @@ namespace: toolhive-system
resources: resources:
- mcp-kube-rbac.yaml - mcp-kube-rbac.yaml
- mcpserver-gitea.yaml - mcp-servers/
- mcpserver-argocd.yaml - registry/
- mcpserver-kubernetes.yaml - vmcp-servers/
- mcp-group-homelab-core.yaml
- ingressroute.yaml - ingressroute.yaml
- secrets/gitea-mcp-secret.sealed.secret.yaml - secrets/gitea-mcp-secret.sealed.secret.yaml
- secrets/argocd-mcp-secret.sealed.secret.yaml - secrets/argocd-mcp-secret.sealed.secret.yaml
- mcp-tool-config-state-docs.yaml - mcp-tool-config-state-docs.yaml
- mcp-tool-config-ops.yaml - mcp-tool-config-ops.yaml
- mcp-tool-config-dev.yaml - mcp-tool-config-dev.yaml
- embedding-server.yaml
- mcp-group-homelab-core.yaml
+14 -29
View File
@@ -7,35 +7,20 @@ metadata:
apiVersion: rbac.authorization.k8s.io/v1 apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole kind: ClusterRole
metadata: metadata:
name: mcp-kubernetes-readonly name: mcp-kubernetes-admin
namespace: toolhive-system namespace: toolhive-system
rules: rules:
- apiGroups: [""] - apiGroups: ["*"]
resources: resources: ["*"]
- pods verbs:
- pods/log - get
- pods/status - list
- services - watch
- endpoints - create
- events - update
- namespaces - patch
- nodes - delete
- configmaps - deletecollection
- persistentvolumeclaims
- replicationcontrollers
verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
resources: ["deployments", "replicasets", "statefulsets", "daemonsets"]
verbs: ["get", "list", "watch"]
- apiGroups: ["batch"]
resources: ["jobs", "cronjobs"]
verbs: ["get", "list", "watch"]
- apiGroups: ["networking.k8s.io"]
resources: ["ingresses", "networkpolicies"]
verbs: ["get", "list", "watch"]
- apiGroups: ["argoproj.io"]
resources: ["applications", "applicationsets", "appprojects"]
verbs: ["get", "list", "watch"]
- apiGroups: ["metrics.k8s.io"] - apiGroups: ["metrics.k8s.io"]
resources: ["pods", "nodes"] resources: ["pods", "nodes"]
verbs: ["get", "list"] verbs: ["get", "list"]
@@ -43,12 +28,12 @@ rules:
apiVersion: rbac.authorization.k8s.io/v1 apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding kind: ClusterRoleBinding
metadata: metadata:
name: mcp-kubernetes-readonly name: mcp-kubernetes-admin
namespace: toolhive-system namespace: toolhive-system
roleRef: roleRef:
apiGroup: rbac.authorization.k8s.io apiGroup: rbac.authorization.k8s.io
kind: ClusterRole kind: ClusterRole
name: mcp-kubernetes-readonly name: mcp-kubernetes-admin
subjects: subjects:
- kind: ServiceAccount - kind: ServiceAccount
name: kubernetes-mcp name: kubernetes-mcp
@@ -0,0 +1,13 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: toolhive-system
resources:
- mcpserver-gitea.yaml
- mcpserver-radar.yaml
- mcpremoteproxy-automem.yaml
- mcpremoteproxy-radar.yaml
- mcpserver-argocd.yaml
- mcpserver-kubernetes.yaml
- mcp-headless-services.yaml
@@ -0,0 +1,56 @@
apiVersion: v1
kind: Service
metadata:
name: gitea-mcp
namespace: toolhive-system
labels:
app: gitea-mcp
toolhive: "true"
toolhive-name: gitea-mcp
spec:
clusterIP: None
publishNotReadyAddresses: true
selector:
app: gitea-mcp
ports:
- name: mcp
port: 8080
targetPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: argocd-mcp
namespace: toolhive-system
labels:
app: argocd-mcp
toolhive: "true"
toolhive-name: argocd-mcp
spec:
clusterIP: None
publishNotReadyAddresses: true
selector:
app: argocd-mcp
ports:
- name: mcp
port: 8080
targetPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: kubernetes-mcp
namespace: toolhive-system
labels:
app: kubernetes-mcp
toolhive: "true"
toolhive-name: kubernetes-mcp
spec:
clusterIP: None
publishNotReadyAddresses: true
selector:
app: kubernetes-mcp
ports:
- name: mcp
port: 8080
targetPort: 8080
@@ -0,0 +1,32 @@
apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPRemoteProxy
metadata:
name: automem
namespace: toolhive-system
labels:
app.kubernetes.io/environment: production
app.kubernetes.io/part-of: automem
annotations:
toolhive.stacklok.dev/registry-export: "true"
toolhive.stacklok.dev/registry-title: AutoMem MCP
toolhive.stacklok.dev/registry-description: AutoMem MCP bridge for persistent cross-session memory.
toolhive.stacklok.dev/registry-url: http://mcp-automem-remote-proxy.toolhive-system.svc.cluster.local:8080
spec:
remoteUrl: http://automem-mcp-bridge.automem:8080/mcp
transport: streamable-http
proxyPort: 8080
groupRef:
name: homelab-core
headerForward:
addHeadersFromSecret:
- headerName: X-API-Key
valueSecretRef:
name: automem-mcp-client-auth
key: authorization
resourceOverrides:
proxyDeployment:
annotations:
glance/parent: automem
proxyService:
annotations:
glance/parent: automem
@@ -0,0 +1,24 @@
apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPRemoteProxy
metadata:
name: radar
namespace: toolhive-system
annotations:
toolhive.stacklok.dev/registry-export: "true"
toolhive.stacklok.dev/registry-title: Radar MCP
toolhive.stacklok.dev/registry-description: Radar MCP Server
toolhive.stacklok.dev/registry-url: https://radar.olb42.com/mcp
glance/parent: radar
spec:
remoteUrl: http://radar.radar:9280/mcp
transport: streamable-http
proxyPort: 8080
groupRef:
name: homelab-core
resourceOverrides:
proxyDeployment:
annotations:
glance/parent: radar
proxyService:
annotations:
glance/parent: radar
@@ -0,0 +1,59 @@
apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPServer
metadata:
name: argocd-mcp
namespace: toolhive-system
annotations:
toolhive.stacklok.dev/registry-export: "true"
toolhive.stacklok.dev/registry-title: Argo CD MCP
toolhive.stacklok.dev/registry-description: Write-capable Argo CD MCP server for inspecting and operating homelab GitOps applications and resources.
toolhive.stacklok.dev/registry-url: http://mcp-argocd-mcp-proxy.toolhive-system.svc.cluster.local:8080/mcp
glance/parent: argocd
spec:
# argoproj-labs MCP server for Argo CD. v0.7.0 starts streamable HTTP on
# port 3000 by default; setting args: ["stdio"] makes the image try to run
# /app/stdio and crash.
image: ghcr.io/argoproj-labs/mcp-for-argocd:v0.7.0
transport: streamable-http
mcpPort: 3000
groupRef:
name: homelab-core
env:
- name: ARGOCD_BASE_URL
value: http://argocd-server.argocd
# argocd-server serves a self-signed cert in-cluster.
- name: NODE_TLS_REJECT_UNAUTHORIZED
value: "0"
- name: MCP_READ_ONLY
value: "false"
# ToolHive 0.28.3 does not translate spec.secrets into the workload, so inject
# the token natively on the `mcp` container via podTemplateSpec.
resourceOverrides:
proxyDeployment:
annotations:
glance/parent: argocd
podTemplateSpec:
metadata:
annotations:
glance/parent: argocd
spec:
groupRef:
name: homelab-core
containers:
- name: mcp
env:
- name: ARGOCD_API_TOKEN
valueFrom:
secretKeyRef:
name: argocd-mcp-secret
key: token
permissionProfile:
type: builtin
name: network
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
@@ -3,6 +3,12 @@ kind: MCPServer
metadata: metadata:
name: gitea-mcp name: gitea-mcp
namespace: toolhive-system namespace: toolhive-system
annotations:
toolhive.stacklok.dev/registry-export: "true"
toolhive.stacklok.dev/registry-title: Gitea MCP
toolhive.stacklok.dev/registry-description: Gitea MCP server for repository, issue, and pull request workflows in the homelab Gitea instance.
toolhive.stacklok.dev/registry-url: http://mcp-gitea-mcp-proxy.toolhive-system.svc.cluster.local:8080/mcp
glance/parent: gitea
spec: spec:
# Upstream Gitea MCP server. Speaks stdio; ToolHive's proxy runner wraps it and # Upstream Gitea MCP server. Speaks stdio; ToolHive's proxy runner wraps it and
# exposes streamable-http at http://mcp-gitea-mcp-proxy.mcp-services:8080/mcp. # exposes streamable-http at http://mcp-gitea-mcp-proxy.mcp-services:8080/mcp.
@@ -10,6 +16,8 @@ spec:
transport: stdio transport: stdio
proxyMode: streamable-http proxyMode: streamable-http
proxyPort: 8080 proxyPort: 8080
groupRef:
name: homelab-core
# No args: the image's default command already runs the binary in stdio mode. # No args: the image's default command already runs the binary in stdio mode.
# (Passing "-t stdio" replaced the command and execed "-t" directly.) # (Passing "-t stdio" replaced the command and execed "-t" directly.)
env: env:
@@ -17,8 +25,17 @@ spec:
value: http://gitea-ha-http.apps:3000 value: http://gitea-ha-http.apps:3000
# NOTE: ToolHive 0.28.3 does not translate spec.secrets into the workload, so # NOTE: ToolHive 0.28.3 does not translate spec.secrets into the workload, so
# inject the token natively on the `mcp` container via podTemplateSpec. # inject the token natively on the `mcp` container via podTemplateSpec.
resourceOverrides:
proxyDeployment:
annotations:
glance/parent: gitea
podTemplateSpec: podTemplateSpec:
metadata:
annotations:
glance/parent: gitea
spec: spec:
groupRef:
name: homelab-core
containers: containers:
- name: mcp - name: mcp
env: env:
@@ -0,0 +1,39 @@
apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPServer
metadata:
name: kubernetes-mcp
namespace: toolhive-system
annotations:
toolhive.stacklok.dev/registry-export: "true"
toolhive.stacklok.dev/registry-title: Kubernetes MCP
toolhive.stacklok.dev/registry-description: Write-capable Kubernetes MCP server for cluster inspection, troubleshooting, and GitOps maintenance actions.
toolhive.stacklok.dev/registry-url: http://mcp-kubernetes-mcp-proxy.toolhive-system.svc.cluster.local:8080/mcp
spec:
# containers/kubernetes-mcp-server. Authenticates to the API in-cluster via the
# kubernetes-mcp ServiceAccount (write-capable ClusterRole, see rbac file). Speaks
# stdio; ToolHive proxies to streamable-http at
# http://mcp-kubernetes-mcp-proxy.mcp-services:8080/mcp.
image: ghcr.io/containers/kubernetes-mcp-server:latest
transport: stdio
# The current image's default CMD starts HTTP mode with `--port 8080`.
# Override args so ToolHive's stdio proxy talks to a stdio MCP server.
args:
- --log-file
- stderr
proxyMode: streamable-http
proxyPort: 8080
groupRef:
name: homelab-core
# Pin the MCP server pod to the ServiceAccount that carries its Kubernetes API
# write permissions.
serviceAccount: kubernetes-mcp
permissionProfile:
type: builtin
name: network
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
@@ -0,0 +1,16 @@
apiVersion: toolhive.stacklok.dev/v1alpha1
kind: MCPServerEntry
metadata:
name: radar
namespace: toolhive-system
annotations:
toolhive.stacklok.dev/registry-export: "true"
toolhive.stacklok.dev/registry-title: Radar MCP
toolhive.stacklok.dev/registry-description: Radar MCP Server
toolhive.stacklok.dev/registry-url: https://radar.olb42.com/mcp
glance/parent: radar
spec:
remoteUrl: http://radar.radar:9280/mcp
transport: streamable-http
groupRef:
name: homelab-core
@@ -1,10 +1,10 @@
apiVersion: toolhive.stacklok.dev/v1alpha1 apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPToolConfig kind: MCPToolConfig
metadata: metadata:
name: dev-tools name: dev-tools
namespace: toolhive-system namespace: toolhive-system
spec: spec:
filter: toolsFilter:
- search_code - search_code
- get_file - get_file
- list_pull_requests - list_pull_requests
@@ -13,7 +13,7 @@ spec:
- memory_search - memory_search
- get_project_summary - get_project_summary
- get_architecture_notes - get_architecture_notes
overrides: toolsOverride:
search_code: search_code:
name: gitea_search_code name: gitea_search_code
description: "Search code in Gitea repos for implementation details." description: "Search code in Gitea repos for implementation details."
@@ -1,10 +1,10 @@
apiVersion: toolhive.stacklok.dev/v1alpha1 apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPToolConfig kind: MCPToolConfig
metadata: metadata:
name: ops-tools name: ops-tools
namespace: toolhive-system namespace: toolhive-system
spec: spec:
filter: toolsFilter:
- get_application - get_application
- get_application_history - get_application_history
- get_application_health - get_application_health
@@ -13,7 +13,7 @@ spec:
- describe_pod - describe_pod
- get_pod_logs - get_pod_logs
- get_events - get_events
overrides: toolsOverride:
get_application: get_application:
name: argocd_get_application name: argocd_get_application
get_application_health: get_application_health:
@@ -1,18 +1,40 @@
apiVersion: toolhive.stacklok.dev/v1alpha1 apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPToolConfig kind: MCPToolConfig
metadata: metadata:
name: state-doc-tools name: state-doc-tools
namespace: toolhive-system namespace: toolhive-system
spec: spec:
filter: toolsFilter:
- get_application - list_org_repos
- get_application_health - search_repos
- get_application_history - get_repository_tree
- get_pods - get_dir_contents
- describe_pod - get_file_contents
- get_events - list_branches
- get_pod_logs - list_commits
- get_commit
- create_or_update_file - create_or_update_file
- get_file - recall_memory
- memory_search - store_memory
- upsert_memory - update_memory
- associate_memories
- list_applications
- get_application
- get_application_resource_tree
- get_application_managed_resources
- get_application_workload_logs
- get_application_events
- get_resource_events
- get_resources
- configuration_view
- namespaces_list
- events_list
- pods_get
- pods_list
- pods_list_in_namespace
- pods_log
- pods_top
- nodes_top
- nodes_stats_summary
- resources_get
- resources_list
@@ -1,46 +0,0 @@
apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPServer
metadata:
name: argocd-mcp
namespace: toolhive-system
spec:
# argoproj-labs MCP server for Argo CD. The image entrypoint already launches
# the server (default stdio transport); ToolHive proxies it to streamable-http
# at http://mcp-argocd-mcp-proxy.mcp-services:8080/mcp.
# NOTE: do NOT set args — the image ENTRYPOINT is `node` and any args replace
# the script path (e.g. "stdio" -> node stdio -> "Cannot find module /app/stdio").
image: ghcr.io/argoproj-labs/mcp-for-argocd:v0.7.0
transport: stdio
proxyMode: streamable-http
proxyPort: 8080
env:
- name: ARGOCD_BASE_URL
value: https://argocd-server.argocd.svc.cluster.local
# argocd-server serves a self-signed cert in-cluster.
- name: NODE_TLS_REJECT_UNAUTHORIZED
value: "0"
# Start read-only; drop this to enable sync/write tools later.
- name: MCP_READ_ONLY
value: "true"
# ToolHive 0.28.3 does not translate spec.secrets into the workload, so inject
# the token natively on the `mcp` container via podTemplateSpec.
podTemplateSpec:
spec:
containers:
- name: mcp
env:
- name: ARGOCD_API_TOKEN
valueFrom:
secretKeyRef:
name: argocd-mcp-secret
key: token
permissionProfile:
type: builtin
name: network
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
@@ -1,27 +0,0 @@
apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPServer
metadata:
name: kubernetes-mcp
namespace: toolhive-system
spec:
# containers/kubernetes-mcp-server. Authenticates to the API in-cluster via the
# kubernetes-mcp ServiceAccount (read-only ClusterRole, see rbac file). Speaks
# stdio; ToolHive proxies to streamable-http at
# http://mcp-kubernetes-mcp-proxy.mcp-services:8080/mcp.
image: ghcr.io/containers/kubernetes-mcp-server:latest
transport: stdio
proxyMode: streamable-http
proxyPort: 8080
# Pin the MCP server pod to our read-only ServiceAccount. The ClusterRole is
# the real guardrail: even if a write tool is invoked, the API rejects it.
serviceAccount: kubernetes-mcp
permissionProfile:
type: builtin
name: network
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
@@ -0,0 +1,75 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: k8s-registry-api-discovery
rules:
- apiGroups:
- toolhive.stacklok.dev
resources:
- mcpservers
- mcpremoteproxies
- virtualmcpservers
- mcpserverentries
- mcpgroups
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- services
verbs:
- get
- list
- watch
- apiGroups:
- gateway.networking.k8s.io
resources:
- httproutes
- gateways
verbs:
- get
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: k8s-registry-api-discovery
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: k8s-registry-api-discovery
subjects:
- kind: ServiceAccount
name: k8s-registry-registry-api
namespace: toolhive-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: k8s-registry-api-events
namespace: toolhive-system
rules:
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: k8s-registry-api-events
namespace: toolhive-system
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: k8s-registry-api-events
subjects:
- kind: ServiceAccount
name: k8s-registry-registry-api
namespace: toolhive-system
@@ -0,0 +1,26 @@
apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPRegistry
metadata:
name: k8s-registry
spec:
pgpassSecretRef:
name: toolhive-reg-pg-app
key: pgpass
podTemplateSpec:
metadata:
annotations:
glance/parent: toolhive
configYAML: |
database:
host: toolhive-reg-pg-rw
port: 5432
user: toolhive-registry
database: toolhive-reg-pg
sources:
- name: k8s
kubernetes: {}
registries:
- name: default
sources: ["k8s"]
auth:
mode: anonymous
@@ -0,0 +1,10 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: toolhive-system
resources:
- k8s-registry.yaml
- k8s-registry-rbac.yaml
- toolhive-registry-backup.yaml
- toolhive-registry-postgres.yaml
@@ -0,0 +1,28 @@
apiVersion: barmancloud.cnpg.io/v1
kind: ObjectStore
metadata:
name: minio-store
namespace: toolhive-system
spec:
configuration:
destinationPath: s3://cnpg-backup/backup
endpointURL: http://ventoux.olb42.com:9000
s3Credentials:
accessKeyId:
name: cnpg-backup
key: AWS_ACCESS_KEY_ID
secretAccessKey:
name: cnpg-backup
key: AWS_SECRET_ACCESS_KEY
wal:
compression: gzip
retentionPolicy: "14d"
instanceSidecarConfiguration:
retentionPolicyIntervalSeconds: 1800
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 500m
memory: 256Mi
@@ -0,0 +1,30 @@
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: toolhive-reg-pg
namespace: toolhive-system
spec:
instances: 2
storage:
storageClass: local-postgres
size: 8Gi
affinity:
enablePodAntiAffinity: true
podAntiAffinityType: required
topologyKey: topology.kubernetes.io/zone
plugins:
- name: barman-cloud.cloudnative-pg.io
isWALArchiver: true
enabled: true
parameters:
barmanObjectName: minio-store
bootstrap:
initdb:
database: toolhive-reg-pg
owner: toolhive-registry
postInitSQL:
- CREATE ROLE toolhive_registry_server;
postgresql:
parameters:
max_connections: "200"
shared_buffers: "256MB"
@@ -5,17 +5,16 @@ metadata:
annotations: annotations:
sealedsecrets.bitnami.com/cluster-wide: "true" sealedsecrets.bitnami.com/cluster-wide: "true"
name: argocd-mcp-secret name: argocd-mcp-secret
namespace: mcp-services namespace: toolhive-system
spec: spec:
encryptedData: encryptedData:
token: AgAJEvZxMyF5Thih458HCAnZK3kopim0EgqkdYp4HExCaPXlJkjTCXLaLtnRRzPOhiVNPNMcasKxvMFcyG7gFW8Bt4mzd4YRgDZ3YUVAOh82qFlo+FuHs9DgG/ZtwX7k8W+ef1vCaWNzPyCn+GLz0vh1bYB4EK2yucdPTyRuHjkWN+14ZfBDsx/K1jml656MH2mSzgp+phjE9PqnlSKwMGfzJpVIg4meOZUvyIQ/pix1M45nFbj3uYAaHctB00+xRQJVpq5Nom2+vCCy/nEI18lmvuSc9RYw53pP50sHe6nRP/sXWWHog6ECAykBQxFtWlWGoFqQ3v/Gc5qgOiqrgbRwIGagJVKpBX1Hcs5tX2luTidaT/cdmu+1te1wRvPCgq6vlMw875cPSybpLz3T/OpMbqqO0oNtxsmjoZe1ebtD7caCFRjyPAxj//vRha6Nw/yGxRhOGNqtxhEcj7OnyezO9qYKNeM2r4EKwsBiLkZbRcMbNmZl7T41lWohT2lV54uzpKU6k81XPERif+PYhC/SbQ6jg40fovL94F2tlI8RDdHzSMRAFJB5lwjNGwmonwMC9TUzW5jA3iIj/CavWvOSNX1flD0vqbau9+wdRh8pRuXDagwlKCZMOFamch0RrBPUJI2qy6ZP99o9TN+SxBnrdhhZdDcM84Gazj2uwDPirrWQ9sKjrLRxJMryUF0pr8PTcT0dsUc52oXWJS/FAaBS0CKRtiVhL273hLK5/bTI31sYDgICd/0sHsro/GSY02f+a3OiGiCWHYdwoluHka77reH9Fl1RDgQUzK3dnhFFJkeqWznv4dmRYinJhgv8GkjjYVR6zWfHP66MEIhhA9j5iIfLgnQGz+gfLN9PlCg9W1akipZ/dwMQa8jTEW8+7bKAodJjCIeZ/215ARHmuHhVDOFdQdkihtsfxnzJTLVJwyzXAvKhthFVLVYRkNu1zRCGvThYhG1W3lw3Qp9nvBPiGD7/dYQMCyUltVconKopTRJuhp+bhSEcI43R8g4dUjUP token: AgAZHSkWcIUeJpb10rUNdg/4cwPdM8s38Ftuc2OryBERx0Fos7z5NGkVl1R+ZbG3xcQofgcvlsESi2Qjo8X18lMBZzj3Oup2khIQqKuieUaVzIC0RsGDrrpeL05XbmvkrTB7Pvv88jLfWMq7hTAGOG2YQT2PKQT2DroY49z3x5TubnJIWFUgav2KZBWkHnCmFFO4kJ/uw6zQSeIkHPLUUZceBb5BrLa1IgMYjnS3nip325/wKyEw/LQGPl4qdnRk4wVk7zdQRGtghY6UtcW6UxElMi/daz+XES4Oqi+lXVcjefgDTC+u9+EEbNbbzXfBk/LFaACgKk71xIyXFAJi4tkNEUssCGljKYz/CXdePHIe9s7n1RzENpCe9lU1IVbLGtCiIpktyK7RE4Tven1r4cZw1LfetmvN8XRdIpW5vyXFh/o4drLV1IXHmar9eCxcD8n1mSRVmCJUVq0ipL6oFAnVSiKPPq4LiRBVoKutRCuy9SAyeoCkToAQofm2zBRkLKq7THVZFMGkstp8DC+yrtFwNXwdUQuLsHSeM4KH4rPwbMuFLgL0GKSb28/puZZHZvD0TJPd+3ei5/6EcXRSulPIUEnYs/pgUMHcOlqiY9oBMRaxSiZXpmRgJczagtOJKZLrFloTx69T2q6ld3vNIVRYMoFktnaPx0riqBUDY4BTRNGRfKuBN6G3fhoC7p0vPgCFWFuIbGJviCJDtD2TpgeKi9otb/cKKPg+/XyZ+AWyfjlPVnZDtIS7OcjurCy8+XrDB7N6cID9+76sQS27AEglww8uQGCpsVdzwu8ldka+n3zsoxPz5UOEkIdwfVPaF+h0YKZhgxpiQI5kRGSp8G+OlAbd12maHxYBc4aFDaB6mTVnY9CS8WlCWVmDw+Ose2FcWdScXvSnag8ig5mA/Tyi8cb19OKI10FAcUtMeGaQZsoppM9r1PWikzFYeb/nksvv688x/vEasxJzeGXbe1bbZ8RlSa1n/OjYkUvMMeqHii4=
template: template:
metadata: metadata:
annotations: annotations:
reflector.v1.k8s.emberstack.com/reflection-allowed: "true" reflector.v1.k8s.emberstack.com/reflection-allowed: "true"
reflector.v1.k8s.emberstack.com/reflection-auto-enabled: "true" reflector.v1.k8s.emberstack.com/reflection-auto-enabled: "true"
reflector.v1.k8s.emberstack.com/reflection-auto-namespaces: mcp-services, reflector.v1.k8s.emberstack.com/reflection-auto-namespaces: toolhive-system
toolhive-system
sealedsecrets.bitnami.com/cluster-wide: "true" sealedsecrets.bitnami.com/cluster-wide: "true"
name: argocd-mcp-secret name: argocd-mcp-secret
namespace: mcp-services namespace: toolhive-system
@@ -5,17 +5,16 @@ metadata:
annotations: annotations:
sealedsecrets.bitnami.com/cluster-wide: "true" sealedsecrets.bitnami.com/cluster-wide: "true"
name: gitea-mcp-secret name: gitea-mcp-secret
namespace: mcp-services namespace: toolhive-system
spec: spec:
encryptedData: encryptedData:
token: AgCJsZ0XkbDWOQ7wxJwV4XJddu4Si+bbiH83iGQ2Jyju5Yp3XsXwE+BHy+cJt8JplAaqOUlz1BeOyudoSvChFV+MtlhfXPP18jHs5BG8BGE0Mz2uaMmQH8nLsHjJ77x/w/+rNtH6ECg9KFOBIG0DAX36EraSiqFgPF67lD4/3P5q1OZr1n1ytn4oUFLJCezJXLhEm05NfI5IfJx+UULyxdhJDPrJNYsan8Vdjk6m+iEv37ryFqXMpSlL2BFUQ+4Ss92jDBK6C127GXfW4LOL1Xq0g2K6KMH3nScKQzsjoM2EfUfCXaOmqjAeyWlK2Bjsz/KvDfnoSZSAoZJOJsAsgV51/XKCP2V7NlaraxwyMjUJNEoBYPkMVJvd2QMXZgEjf+vBNLjS1euMCwZPqG0Fg015Yx0kXEOOtRewOafP+5bK7mXwMsGIsXMlNGWMkQigOWSXXPAjO2TRK7gSTEyN+QaJDDisdSV8+8xlTZ92ldIchin24ztsp14kP+vVy4jv2SLa0i7O3XV23UHB7QnCVhaPbo0hVhB1bVRz0QPuFkmuvLRyb6cm85NxeYxGkExtbQk020V2Y9upz4bV6sB6y8IIL5TR3jFr3zhYeO7Su5rA/r3Jt8XO17Ljx/DngpynVyJvZbpwstDL6se22es15HfUTixL90WDLWM1/xMt3dbuVkIPgj7Wes9fLNLvn+khal0XkqS2bUa9Izl3GqFlNeBa5Z0i4RY8m3m1xn+9j3dZlwlW0CXrBW7z token: AgA0fmH6lbaZRX8SRUVl1br+rDEe16Tm+GJUyOfg0zAclPOjgInfV4dV4uPNAvWRyrJQfhZ/S7uSh68wz+yRcMEL8ZEIMqoh1NvzckhocUehos7qPGu/4iBJK9GSYW2xLbT8dmVD+QtOVtTvEHHJEieIVIw1fj/W+JxLUite/ZlE0loAVKnBRgauvO36bjpO/n0pLXeQF3ymEyIEC1WvrLfWoPOlaQc1EfUsKeqRHa3DNEP6TDiM0xF7qdmiMvQBslvYJ+TkqZDjv3m9axhJiQPOOWZVG1KDogXniG8i4mpjXdDAbdM4rgGmI56Yj1QZ2cxb1EaS80DmormBxtXmMEGLAPuUs1W3lxTj0Zdz1NDA06rQfFhumirggbZRiLB8HD+FLygdcUQGxWWt18uPWx+1QoAvOLqzCfQphrDcg+D+NhCamAkoo0QxzjOPoTQ5q3GabVyHvxkBrp+Tj9RX3EGaRGCZbI9M3/DC8H2Kl3lm1Evumo2cJalCV1Uu0n1wj5ZtsyeuZnmtFISTvhNNZOE4qEMvKrgvHBf6WC5FLLX5VlrMJtjSgdl8NvmZSWEmOGXT6JdRN+HAU0XejWmXbJmezaMTukowqVtqJuGEidZrcLWpgWMHVfYqjjC7glQxKY6F7b95UxM42QStZ0ZQ1NgoYQgoQdgz02kXoq17VvPpdNycR/lCN1/fmVyjC4yBbHyWkXsShH8uPfMpVvYNWtwZf+TTDfKV4xBQILiGSEouIiRLaX8FTIkF
template: template:
metadata: metadata:
annotations: annotations:
reflector.v1.k8s.emberstack.com/reflection-allowed: "true" reflector.v1.k8s.emberstack.com/reflection-allowed: "true"
reflector.v1.k8s.emberstack.com/reflection-auto-enabled: "true" reflector.v1.k8s.emberstack.com/reflection-auto-enabled: "true"
reflector.v1.k8s.emberstack.com/reflection-auto-namespaces: mcp-services, reflector.v1.k8s.emberstack.com/reflection-auto-namespaces: toolhive-system
toolhive-system
sealedsecrets.bitnami.com/cluster-wide: "true" sealedsecrets.bitnami.com/cluster-wide: "true"
name: gitea-mcp-secret name: gitea-mcp-secret
namespace: mcp-services namespace: toolhive-system
@@ -0,0 +1,7 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: toolhive-system
resources:
- public-mcp-secret.sealed.secret.yaml
@@ -0,0 +1,22 @@
---
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
annotations:
sealedsecrets.bitnami.com/cluster-wide: "true"
name: public-mcp-secret
namespace: keycloak
spec:
encryptedData:
client-id: AgANqLN6opyrUHiqVaUKvHwUr4chY38qb03WxUzXWll6SDh7bRvHcZ3wAMHfsmigEz2cSWVMWg0VmEcP16r6gcEiYGQ2/Ol182oXbtI/bWad/3rFFzMlLrKie8H9oGS/LgyRyhEiQ2hDzsdAJWARdHrRhbpFvJ1QeUJtcIBGKy8CcjTm8YfW7u/IqNyo0X+NIK2vImO9UdrmzIIDwQav0e30dRkmtbL5lamR563Qa1k4alEdOTF/E2fe6OVxaIqjpbzHnjmbKRA1ymhYGOasm8hTUeE/IVicAZNeQAg0ps31PSHpwjnEzyDZ1k7p5Dvc4+RhNXhOmONnI38/EbTA0dXra2ZeRxdcmErGrN2KrVZmlxyBK3462z8yWbiGU4esAdHJAdAjBkD+sDP2jYIsy7wvzArYM/hbFqDBrLs9vf29bYyUfRoRo/0BS+iO06zBjr0ssUT95FBrs1RLXDJUaomFkylz32L+jLfalKc4N1xeIwA76VOk4m3lVllmZP0YFC/mifHJ6qzuOgJqBw8fTkYhASiwyfsbbk3c8f4VlHqvXPKhJKkJvaUMMve59XpKuVX8O3phW2nJG4hl86OVkfOQRIZgPqn6t5UiHyJCPv6JoxAITs40thG06QUn263MTyZyaNGw9/PPVmSO/O5N2DIElWl75FpAEg3fqsljJiq2NGVQWLmT3C7tdyUwDEuu0r91cQmfUY7EehBD
client-secret: AgCCe5CH8xoDedXE9iM4GGEw/K7LhdXzH3lPynjlJ85OdMLuM6yYkaN37xF9FbdwhkQQnX3pjM08ILjEnpWtIx8zNmzTl+U90sSo85YqbSyZcNK7uy3oCTaRB6sdtPmdcDWEjtUcvv7+2WZcnAH8IfpT7wpesrjkO7uND0ZFX2bqhR26goq40gSiNahfCLp5QkZlsnTb6r6uw2N0utOLFDp3m233Nh268kxamlvr8E1IYDZFBC8KDIz9rfKvuMNBV6CA++FDeYybS1WNkgK3hQ+tGRVy5L7zB6x06zKzh4UIBn1t9sEga1x2ZH2Szgcb6EgBXmQ3rFaJ7O52dUltLV4GHX4uqRmjj+aZFQQuaJuvgp1Dc0rhFFwKveH5R0VcEarSDHeRlQmPiszKTsk8tgfCw8U64uoe6ACPq0isWVYBvUxttm/nB3MNSEl3TOquw9UtsiV1CaqC5LpI4qO1EatpARF57uqxw1Ewl8e8WrcBQ3WlI+7kjsJ2jHODx8sTlByqW7PZeJB4pk8sIq3NXA4VK/7f+852itxE0R7S67nZ4xFi75V6omyaEcniDVaPzxoC6EiFsPrUj8QpA+eRlKZRFTS4fmQRUkKVGYEnSWxDTkM1ot5dPx1MkA6MsEwq7wiuZwIbXeLK9Z3NqqsJ5LyTwidXhim5vf4iMHqH6Fj9ZL0RZTjMqfLXSjDD+Tu9qwMnXfkZx6EMsOLKc5uz73lP2VpGoUyq9ndqHsEbqYjbHQ==
template:
metadata:
annotations:
reflector.v1.k8s.emberstack.com/reflection-allowed: "true"
reflector.v1.k8s.emberstack.com/reflection-auto-enabled: "true"
reflector.v1.k8s.emberstack.com/reflection-auto-namespaces: keycloak, toolhive-system
sealedsecrets.bitnami.com/cluster-wide: "true"
sealedsecrets.bitnami.com/managed: "true"
name: public-mcp-secret
namespace: keycloak
@@ -0,0 +1,25 @@
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: vmcp-dev-safe-ingress
namespace: toolhive-system
labels:
app.kubernetes.io/name: dev-safe-vmcp
annotations:
dns.public: 'true'
dns.public.access.policy: bypass
dns.public.hostname: dev-safe.olb42.com
spec:
entryPoints:
- websecure
routes:
- kind: Rule
match: Host(`dev-safe.olb42.com`)
services:
- name: vmcp-dev-safe-vmcp
namespace: toolhive-system
port: 4483
# No default TLSStore in this cluster, so reference the wildcard cert
# explicitly. olb42-wildcard-tls is auto-reflected into every namespace.
tls:
secretName: olb42-wildcard-tls
@@ -0,0 +1,33 @@
apiVersion: toolhive.stacklok.dev/v1beta1
kind: VirtualMCPServer
metadata:
name: dev-safe-vmcp
namespace: toolhive-system
annotations:
toolhive.stacklok.dev/registry-export: "true"
toolhive.stacklok.dev/registry-title: Dev Safe Virtual MCP
toolhive.stacklok.dev/registry-description: Development-focused virtual MCP combining safe Gitea and AutoMem tools.
toolhive.stacklok.dev/registry-url: http://vmcp-dev-safe-vmcp.toolhive-system.svc.cluster.local:4483
spec:
groupRef:
name: homelab-core
embeddingServerRef:
name: homelab-embedding
incomingAuth:
type: anonymous
config:
aggregation:
conflictResolution: prefix
tools:
- workload: gitea-mcp
toolConfigRef:
name: dev-tools
- workload: automem-remote
toolConfigRef:
name: dev-tools
- workload: argocd-mcp
excludeAll: true
- workload: kubernetes-mcp
excludeAll: true
optimizer:
maxToolsToReturn: 5
@@ -0,0 +1,25 @@
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: full-vmcp-ingress
namespace: toolhive-system
labels:
app.kubernetes.io/name: full-vmcp
# annotations:
# dns.public: 'false'
# dns.public.access.policy: google-ws
# dns.public.hostname: full-vmcp.olb42.com
spec:
entryPoints:
- websecure
routes:
- kind: Rule
match: Host(`full-vmcp.olb42.com`)
services:
- name: vmcp-full-vmcp
namespace: toolhive-system
port: 4483
# No default TLSStore in this cluster, so reference the wildcard cert
# explicitly. olb42-wildcard-tls is auto-reflected into every namespace.
tls:
secretName: olb42-wildcard-tls
@@ -0,0 +1,30 @@
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: full-vmcp-ngorse-ingress
namespace: toolhive-system
labels:
app.kubernetes.io/name: full-vmcp
annotations:
dns.internal: 'true'
dns.internal.hostname: full-vmcp.ngorse.com
spec:
entryPoints:
- websecure
routes:
- kind: Rule
match: Host(`mcp.ngorse.com`)
services:
- name: vmcp-full-vmcp
namespace: toolhive-system
port: 4483
- kind: Rule
match: Host(`full-vmcp.ngorse.com`)
services:
- name: vmcp-full-vmcp
namespace: toolhive-system
port: 4483
# No default TLSStore in this cluster, so reference the wildcard cert
# explicitly. olb42-wildcard-tls is auto-reflected into every namespace.
tls:
secretName: ngorse-wildcard-tls
@@ -0,0 +1,39 @@
apiVersion: toolhive.stacklok.dev/v1beta1
kind: VirtualMCPServer
metadata:
name: full-vmcp
namespace: toolhive-system
annotations:
toolhive.stacklok.dev/registry-export: "true"
toolhive.stacklok.dev/registry-title: Full Homelab Virtual MCP
toolhive.stacklok.dev/registry-description: Full virtual MCP exposing the homelab MCP tool group through ToolHive aggregation.
toolhive.stacklok.dev/registry-url: https://mcp.ngorse.com
glance/parent: toolhive
spec:
groupRef:
name: homelab-core
podTemplateSpec:
metadata:
annotations:
glance/parent: toolhive
embeddingServerRef:
name: homelab-embedding
incomingAuth:
type: oidc
oidcConfigRef:
name: public-mcp-oidc
audience: http://full-vmcp.toolhive-system.svc.cluster.local:4483
authServerConfig:
issuer: https://mcp.ngorse.com
upstreamProviders:
- name: keycloak
type: oidc
oidcConfig:
issuerUrl: https://cloak.olb42.com/realms/home-lab
clientId: public-mcp
redirectUri: https://mcp.ngorse.com/oauth/callback
config:
aggregation:
conflictResolution: prefix
optimizer:
maxToolsToReturn: 8
@@ -0,0 +1,19 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: toolhive-system
resources:
- oidcconfig-public-mcp.yaml
- oidcconfig-state-docs-vmcp.yaml
- full-vmcp.yaml
- full-vmcp-ingress.yaml
- full-vmcp-ngorse-ingress.yaml
- dev-safe-vmcp.yaml
- dev-safe-vmcp-ingress.yaml
- ops-safe-vmcp.yaml
- ops-safe-vmcp-ingress.yaml
- state-docs-vmcp.yaml
- state-docs-vmcp-ingress.yaml
- state-docs-ngorse-ingress.yaml
@@ -0,0 +1,13 @@
apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPOIDCConfig
metadata:
name: public-mcp-oidc
namespace: toolhive-system
spec:
type: inline
inline:
issuer: https://mcp.ngorse.com
clientId: public-mcp
clientSecretRef:
name: public-mcp-secret
key: client-secret
@@ -0,0 +1,13 @@
apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPOIDCConfig
metadata:
name: state-docs-vmcp-oidc
namespace: toolhive-system
spec:
type: inline
inline:
issuer: https://state-docs.ngorse.com
clientId: state-docs-vmcp
clientSecretRef:
name: state-docs-vmcp-secret
key: client-secret
@@ -0,0 +1,26 @@
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: vmcp-ops-safe-ingress
namespace: toolhive-system
labels:
app.kubernetes.io/name: ops-safe-vmcp
annotations:
dns.public: 'true'
dns.public.access.policy: bypass
dns.public.hostname: ops-safe.olb42.com
spec:
entryPoints:
- websecure
routes:
- kind: Rule
match: Host(`ops-safe.olb42.com`)
services:
- name: vmcp-ops-safe-vmcp
namespace: toolhive-system
port: 4483
# No default TLSStore in this cluster, so reference the wildcard cert
# explicitly. olb42-wildcard-tls is auto-reflected into every namespace.
tls:
secretName: olb42-wildcard-tls
@@ -0,0 +1,33 @@
apiVersion: toolhive.stacklok.dev/v1beta1
kind: VirtualMCPServer
metadata:
name: ops-safe-vmcp
namespace: toolhive-system
annotations:
toolhive.stacklok.dev/registry-export: "true"
toolhive.stacklok.dev/registry-title: Ops Safe Virtual MCP
toolhive.stacklok.dev/registry-description: Operations-focused virtual MCP combining safe Argo CD and Kubernetes tools.
toolhive.stacklok.dev/registry-url: http://vmcp-ops-safe-vmcp.toolhive-system.svc.cluster.local:4483
spec:
groupRef:
name: homelab-core
embeddingServerRef:
name: homelab-embedding
incomingAuth:
type: anonymous
config:
aggregation:
conflictResolution: prefix
tools:
- workload: gitea-mcp
excludeAll: true
- workload: automem-mcp
excludeAll: true
- workload: argocd-mcp
toolConfigRef:
name: ops-tools
- workload: kubernetes-mcp
toolConfigRef:
name: ops-tools
optimizer:
maxToolsToReturn: 6
@@ -0,0 +1,24 @@
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: state-docs-vmcp-ngorse-ingress
namespace: toolhive-system
labels:
app.kubernetes.io/name: state-docs-vmcp
annotations:
dns.internal: 'true'
dns.internal.hostname: state-docs.ngorse.com
spec:
entryPoints:
- websecure
routes:
- kind: Rule
match: Host(`state-docs.ngorse.com`)
services:
- name: vmcp-state-docs-vmcp
namespace: toolhive-system
port: 4483
# No default TLSStore in this cluster, so reference the wildcard cert
# explicitly. olb42-wildcard-tls is auto-reflected into every namespace.
tls:
secretName: ngorse-wildcard-tls
@@ -0,0 +1,21 @@
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: state-docs-vmcp-ingress
namespace: toolhive-system
labels:
app.kubernetes.io/name: state-docs-vmcp
spec:
entryPoints:
- websecure
routes:
- kind: Rule
match: Host(`state-docs.olb42.com`)
services:
- name: vmcp-state-docs-vmcp
namespace: toolhive-system
port: 4483
# No default TLSStore in this cluster, so reference the wildcard cert
# explicitly. olb42-wildcard-tls is auto-reflected into every namespace.
tls:
secretName: olb42-wildcard-tls
@@ -0,0 +1,40 @@
apiVersion: toolhive.stacklok.dev/v1beta1
kind: VirtualMCPServer
metadata:
name: state-docs-vmcp
namespace: toolhive-system
annotations:
toolhive.stacklok.dev/registry-export: "true"
toolhive.stacklok.dev/registry-title: Document State Virtual MCP
toolhive.stacklok.dev/registry-description: Virtual MCP which is focused on enabling documentation of the current state
toolhive.stacklok.dev/registry-url: https://state-docs.ngorse.com
spec:
groupRef:
name: homelab-core
embeddingServerRef:
name: homelab-embedding
incomingAuth:
type: anonymous
config:
aggregation:
conflictResolution: prefix
excludeAllTools: false
tools:
- workload: gitea-mcp
toolConfigRef:
name: state-doc-tools
- workload: automem
toolConfigRef:
name: state-doc-tools
- workload: argocd-mcp
toolConfigRef:
name: state-doc-tools
- workload: kubernetes-mcp
toolConfigRef:
name: state-doc-tools
- workload: radar
excludeAll: true
compositeTools: []
operational:
failureHandling:
partialFailureMode: best_effort