Compare commits

..
40 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
24 changed files with 330 additions and 60 deletions
+5 -2
View File
@@ -6,7 +6,7 @@ metadata:
spec: spec:
ignoreApplicationDifferences: ignoreApplicationDifferences:
- jsonPointers: - jsonPointers:
- /spec/syncPolicy - /spec/syncPolicy/automated/enabled
goTemplate: true goTemplate: true
goTemplateOptions: ["missingkey=error"] goTemplateOptions: ["missingkey=error"]
generators: generators:
@@ -15,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 }}'
@@ -60,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
+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
@@ -6,6 +6,8 @@ namespace: toolhive-system
resources: resources:
- mcpserver-gitea.yaml - mcpserver-gitea.yaml
- mcpserver-radar.yaml - mcpserver-radar.yaml
- mcpremoteproxy-automem.yaml
- mcpremoteproxy-radar.yaml
- mcpserver-argocd.yaml - mcpserver-argocd.yaml
- mcpserver-kubernetes.yaml - mcpserver-kubernetes.yaml
- mcp-headless-services.yaml - mcp-headless-services.yaml
@@ -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
@@ -6,7 +6,7 @@ metadata:
annotations: annotations:
toolhive.stacklok.dev/registry-export: "true" toolhive.stacklok.dev/registry-export: "true"
toolhive.stacklok.dev/registry-title: Argo CD MCP toolhive.stacklok.dev/registry-title: Argo CD MCP
toolhive.stacklok.dev/registry-description: Read-only Argo CD MCP server for inspecting homelab GitOps applications and resources. 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 toolhive.stacklok.dev/registry-url: http://mcp-argocd-mcp-proxy.toolhive-system.svc.cluster.local:8080/mcp
glance/parent: argocd glance/parent: argocd
spec: spec:
@@ -24,9 +24,8 @@ spec:
# argocd-server serves a self-signed cert in-cluster. # argocd-server serves a self-signed cert in-cluster.
- name: NODE_TLS_REJECT_UNAUTHORIZED - name: NODE_TLS_REJECT_UNAUTHORIZED
value: "0" value: "0"
# Start read-only; drop this to enable sync/write tools later.
- name: MCP_READ_ONLY - name: MCP_READ_ONLY
value: "true" value: "false"
# ToolHive 0.28.3 does not translate spec.secrets into the workload, so inject # ToolHive 0.28.3 does not translate spec.secrets into the workload, so inject
# the token natively on the `mcp` container via podTemplateSpec. # the token natively on the `mcp` container via podTemplateSpec.
resourceOverrides: resourceOverrides:
@@ -6,11 +6,11 @@ metadata:
annotations: annotations:
toolhive.stacklok.dev/registry-export: "true" toolhive.stacklok.dev/registry-export: "true"
toolhive.stacklok.dev/registry-title: Kubernetes MCP toolhive.stacklok.dev/registry-title: Kubernetes MCP
toolhive.stacklok.dev/registry-description: Read-only Kubernetes MCP server for safe cluster inspection and troubleshooting. 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 toolhive.stacklok.dev/registry-url: http://mcp-kubernetes-mcp-proxy.toolhive-system.svc.cluster.local:8080/mcp
spec: spec:
# containers/kubernetes-mcp-server. Authenticates to the API in-cluster via the # containers/kubernetes-mcp-server. Authenticates to the API in-cluster via the
# kubernetes-mcp ServiceAccount (read-only ClusterRole, see rbac file). Speaks # kubernetes-mcp ServiceAccount (write-capable ClusterRole, see rbac file). Speaks
# stdio; ToolHive proxies to streamable-http at # stdio; ToolHive proxies to streamable-http at
# http://mcp-kubernetes-mcp-proxy.mcp-services:8080/mcp. # http://mcp-kubernetes-mcp-proxy.mcp-services:8080/mcp.
image: ghcr.io/containers/kubernetes-mcp-server:latest image: ghcr.io/containers/kubernetes-mcp-server:latest
@@ -20,14 +20,12 @@ spec:
args: args:
- --log-file - --log-file
- stderr - stderr
- --read-only
- --disable-destructive
proxyMode: streamable-http proxyMode: streamable-http
proxyPort: 8080 proxyPort: 8080
groupRef: groupRef:
name: homelab-core name: homelab-core
# Pin the MCP server pod to our read-only ServiceAccount. The ClusterRole is # Pin the MCP server pod to the ServiceAccount that carries its Kubernetes API
# the real guardrail: even if a write tool is invoked, the API rejects it. # write permissions.
serviceAccount: kubernetes-mcp serviceAccount: kubernetes-mcp
permissionProfile: permissionProfile:
type: builtin type: builtin
@@ -3,6 +3,12 @@ kind: MCPServerEntry
metadata: metadata:
name: radar name: radar
namespace: toolhive-system 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: spec:
remoteUrl: http://radar.radar:9280/mcp remoteUrl: http://radar.radar:9280/mcp
transport: streamable-http transport: streamable-http
@@ -5,14 +5,36 @@ metadata:
namespace: toolhive-system namespace: toolhive-system
spec: spec:
toolsFilter: 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
@@ -9,7 +9,8 @@ rules:
- mcpservers - mcpservers
- mcpremoteproxies - mcpremoteproxies
- virtualmcpservers - virtualmcpservers
- mcpserverentry - mcpserverentries
- mcpgroups
verbs: verbs:
- get - get
- list - list
@@ -6,6 +6,10 @@ spec:
pgpassSecretRef: pgpassSecretRef:
name: toolhive-reg-pg-app name: toolhive-reg-pg-app
key: pgpass key: pgpass
podTemplateSpec:
metadata:
annotations:
glance/parent: toolhive
configYAML: | configYAML: |
database: database:
host: toolhive-reg-pg-rw host: toolhive-reg-pg-rw
@@ -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
@@ -1,4 +1,4 @@
apiVersion: toolhive.stacklok.dev/v1alpha1 apiVersion: toolhive.stacklok.dev/v1beta1
kind: VirtualMCPServer kind: VirtualMCPServer
metadata: metadata:
name: dev-safe-vmcp name: dev-safe-vmcp
@@ -5,10 +5,10 @@ metadata:
namespace: toolhive-system namespace: toolhive-system
labels: labels:
app.kubernetes.io/name: full-vmcp app.kubernetes.io/name: full-vmcp
annotations: # annotations:
dns.public: 'true' # dns.public: 'false'
dns.public.access.policy: google-ws # dns.public.access.policy: google-ws
dns.public.hostname: full-vmcp.olb42.com # dns.public.hostname: full-vmcp.olb42.com
spec: spec:
entryPoints: entryPoints:
- websecure - websecure
@@ -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
@@ -1,4 +1,4 @@
apiVersion: toolhive.stacklok.dev/v1alpha1 apiVersion: toolhive.stacklok.dev/v1beta1
kind: VirtualMCPServer kind: VirtualMCPServer
metadata: metadata:
name: full-vmcp name: full-vmcp
@@ -7,14 +7,31 @@ metadata:
toolhive.stacklok.dev/registry-export: "true" toolhive.stacklok.dev/registry-export: "true"
toolhive.stacklok.dev/registry-title: Full Homelab Virtual MCP 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-description: Full virtual MCP exposing the homelab MCP tool group through ToolHive aggregation.
toolhive.stacklok.dev/registry-url: http://vmcp-full-vmcp.toolhive-system.svc.cluster.local:4483 toolhive.stacklok.dev/registry-url: https://mcp.ngorse.com
glance/parent: toolhive
spec: spec:
groupRef: groupRef:
name: homelab-core name: homelab-core
podTemplateSpec:
metadata:
annotations:
glance/parent: toolhive
embeddingServerRef: embeddingServerRef:
name: homelab-embedding name: homelab-embedding
incomingAuth: incomingAuth:
type: anonymous 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: config:
aggregation: aggregation:
conflictResolution: prefix conflictResolution: prefix
@@ -4,9 +4,16 @@ kind: Kustomization
namespace: toolhive-system namespace: toolhive-system
resources: resources:
- oidcconfig-public-mcp.yaml
- oidcconfig-state-docs-vmcp.yaml
- full-vmcp.yaml - full-vmcp.yaml
- full-vmcp-ingress.yaml - full-vmcp-ingress.yaml
- full-vmcp-ngorse-ingress.yaml
- dev-safe-vmcp.yaml - dev-safe-vmcp.yaml
- dev-safe-vmcp-ingress.yaml - dev-safe-vmcp-ingress.yaml
- ops-safe-vmcp.yaml - ops-safe-vmcp.yaml
- ops-safe-vmcp-ingress.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
@@ -1,4 +1,4 @@
apiVersion: toolhive.stacklok.dev/v1alpha1 apiVersion: toolhive.stacklok.dev/v1beta1
kind: VirtualMCPServer kind: VirtualMCPServer
metadata: metadata:
name: ops-safe-vmcp name: ops-safe-vmcp
@@ -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