From dd83ddf28f8e5753783b51761de825ca9d5f2706 Mon Sep 17 00:00:00 2001
From: ChrisJBurns <29541485+ChrisJBurns@users.noreply.github.com>
Date: Tue, 9 Sep 2025 17:14:15 +0100
Subject: [PATCH 1/4] adds docs for using different secrets managers in k8s
Signed-off-by: ChrisJBurns <29541485+ChrisJBurns@users.noreply.github.com>
---
.../{run-mcp-k8s.md => run-mcp-k8s.mdx} | 68 +++++++++++++++++--
1 file changed, 64 insertions(+), 4 deletions(-)
rename docs/toolhive/guides-k8s/{run-mcp-k8s.md => run-mcp-k8s.mdx} (90%)
diff --git a/docs/toolhive/guides-k8s/run-mcp-k8s.md b/docs/toolhive/guides-k8s/run-mcp-k8s.mdx
similarity index 90%
rename from docs/toolhive/guides-k8s/run-mcp-k8s.md
rename to docs/toolhive/guides-k8s/run-mcp-k8s.mdx
index d1f5362e..1111ecf1 100644
--- a/docs/toolhive/guides-k8s/run-mcp-k8s.md
+++ b/docs/toolhive/guides-k8s/run-mcp-k8s.mdx
@@ -253,10 +253,14 @@ process.
### Run a server with secrets
-For MCP servers that require authentication tokens or other secrets, add the
-`secrets` field to the `MCPServer` resource. This example shows how to use a
-Kubernetes secret to pass a GitHub personal access token to the `github` MCP
-server.
+For MCP servers that require authentication tokens or other secrets, you can use
+secrets from multiple secrets managers:
+
+
+
+
+This example shows how to use an existing Kubernetes secret to pass a GitHub
+personal access token to the `github` MCP server.
```yaml {13-16} title="my-mcpserver-with-secrets.yaml"
apiVersion: toolhive.stacklok.dev/v1alpha1
@@ -291,6 +295,62 @@ Apply the MCPServer resource:
kubectl apply -f my-mcpserver-with-secrets.yaml
```
+
+
+
+This example shows how to use an existing Kubernetes secret created by the
+[External Secrets Operator](https://external-secrets.io/) to pass a GitHub
+personal access token to the `github` MCP server.
+
+:::info[Important]
+
+Given the External Secrets Operator creates standard Kubernetes secrets based on
+external secrets, the MCP server definition will look the same as the Kubernetes
+example.
+
+:::
+
+```yaml {13-16} title="my-mcpserver-with-secrets-eso.yaml"
+apiVersion: toolhive.stacklok.dev/v1alpha1
+kind: MCPServer
+metadata:
+ name: github
+ namespace: production # Can be any namespace
+spec:
+ image: ghcr.io/github/github-mcp-server
+ transport: stdio
+ port: 8080
+ permissionProfile:
+ type: builtin
+ name: network
+ secrets:
+ - name: github-token
+ key: token
+ targetEnvName: GITHUB_PERSONAL_ACCESS_TOKEN
+```
+
+First, create the secret by using
+[External Secrets Operator](https://external-secrets.io/latest/api/externalsecret).
+Note that the secret must be created in the same namespace as the MCP server and
+the key must match the one specified in the `MCPServer` resource.
+
+Apply the MCPServer resource:
+
+```bash
+kubectl apply -f my-mcpserver-with-secrets-eso.yaml
+```
+
+
+
+
+This example shows how to use [Vault](https://developer.hashicorp.com/vault) to
+inject secrets into the ToolHive containers for consumption.
+
+Chris to flesh out with Jakub
+
+
+
+
### Mount a volume
You can mount volumes into the MCP server pod to provide persistent storage or
From 31d423ddc7cdcd9e979662c557999c667ac3ce96 Mon Sep 17 00:00:00 2001
From: ChrisJBurns <29541485+ChrisJBurns@users.noreply.github.com>
Date: Tue, 9 Sep 2025 19:01:41 +0100
Subject: [PATCH 2/4] adds vault secret injection docs
Signed-off-by: ChrisJBurns <29541485+ChrisJBurns@users.noreply.github.com>
---
docs/toolhive/guides-k8s/run-mcp-k8s.mdx | 61 +++++++++++++++++++++++-
1 file changed, 60 insertions(+), 1 deletion(-)
diff --git a/docs/toolhive/guides-k8s/run-mcp-k8s.mdx b/docs/toolhive/guides-k8s/run-mcp-k8s.mdx
index 1111ecf1..2c659919 100644
--- a/docs/toolhive/guides-k8s/run-mcp-k8s.mdx
+++ b/docs/toolhive/guides-k8s/run-mcp-k8s.mdx
@@ -346,7 +346,66 @@ kubectl apply -f my-mcpserver-with-secrets-eso.yaml
This example shows how to use [Vault](https://developer.hashicorp.com/vault) to
inject secrets into the ToolHive containers for consumption.
-Chris to flesh out with Jakub
+Injecting secrets using Vault is done with its agent sidecar container, but
+before you can start injecting secrets into the container there are some steps
+to do before hand. This includes setting up Vault to be able to authenticate and
+pull the necessary secrets. We will not detail here how to do this as there are
+some very helpful
+[Vault guides](https://developer.hashicorp.com/vault/tutorials/kubernetes/kubernetes-sidecar)
+on setting this up, but before we can inject secrets into the ToolHive
+containers we need to have the following:
+
+- Vault available
+- Vault configured for Kubernetes authentication
+- Vault policy created to be able to read the desired secrets
+- Vault role created that is bound to the ToolHive ProxyRunner Service Account
+ in order to enable authentication
+
+```yaml {23-33} title="my-mcpserver-with-vault-secrets-injection.yaml"
+apiVersion: toolhive.stacklok.dev/v1alpha1
+kind: MCPServer
+metadata:
+ name: github-vault-generic
+ namespace: toolhive-system
+spec:
+ image: ghcr.io/github/github-mcp-server:latest
+ transport: stdio
+ port: 9095
+ permissionProfile:
+ type: builtin
+ name: network
+ resources:
+ limits:
+ cpu: '100m'
+ memory: '128Mi'
+ requests:
+ cpu: '50m'
+ memory: '64Mi'
+ resourceOverrides:
+ proxyDeployment:
+ podTemplateMetadataOverrides:
+ annotations:
+ # Enable Vault Agent injection
+ vault.hashicorp.com/agent-inject: 'true'
+ vault.hashicorp.com/role: ''
+
+ # Inject GitHub configuration secret
+ vault.hashicorp.com/agent-inject-secret-github-config: 'workload-secrets/data/github-mcp/config'
+ vault.hashicorp.com/agent-inject-template-github-config: |
+ {{- with secret "workload-secrets/data/github-mcp/config" -}}
+ GITHUB_PERSONAL_ACCESS_TOKEN={{ .Data.data.token }}
+ {{- end -}}
+```
+
+Apply the MCPServer resource:
+
+```bash
+kubectl apply -f my-mcpserver-with-vault-secrets-injection.yaml
+```
+
+The Vault agent sidecar will now inject secrets from the
+`workload-secrets/data/github-mcp/config` inside of Vault, into the ProxyRunner
+container.
From e02f6a3948c1c104e77f610dddedfa87578ffc6d Mon Sep 17 00:00:00 2001
From: ChrisJBurns <29541485+ChrisJBurns@users.noreply.github.com>
Date: Tue, 9 Sep 2025 22:11:07 +0100
Subject: [PATCH 3/4] corrects name of k8s docs
Signed-off-by: ChrisJBurns <29541485+ChrisJBurns@users.noreply.github.com>
---
docs/toolhive/guides-cli/advanced-cicd.mdx | 2 +-
docs/toolhive/guides-cli/build-containers.mdx | 4 ++--
docs/toolhive/guides-k8s/deploy-operator-helm.md | 6 +++---
docs/toolhive/guides-k8s/intro.md | 2 +-
docs/toolhive/guides-mcp/filesystem.mdx | 2 +-
docs/toolhive/tutorials/quickstart-k8s.mdx | 5 +++--
6 files changed, 11 insertions(+), 10 deletions(-)
diff --git a/docs/toolhive/guides-cli/advanced-cicd.mdx b/docs/toolhive/guides-cli/advanced-cicd.mdx
index 8113bd5e..36d619f7 100644
--- a/docs/toolhive/guides-cli/advanced-cicd.mdx
+++ b/docs/toolhive/guides-cli/advanced-cicd.mdx
@@ -313,6 +313,6 @@ When implementing advanced CI/CD patterns:
## Related information
- [Build MCP server containers](./build-containers.mdx)
-- [Run MCP servers in Kubernetes](../guides-k8s/run-mcp-k8s.md)
+- [Run MCP servers in Kubernetes](../guides-k8s/run-mcp-k8s.mdx)
- [`thv build` command reference](../reference/cli/thv_build.md)
- [Secrets management](./secrets-management.mdx)
diff --git a/docs/toolhive/guides-cli/build-containers.mdx b/docs/toolhive/guides-cli/build-containers.mdx
index 89e06eb8..a94ba231 100644
--- a/docs/toolhive/guides-cli/build-containers.mdx
+++ b/docs/toolhive/guides-cli/build-containers.mdx
@@ -316,7 +316,7 @@ thv build --tag my-server:dev go:///path/to/my-project
- Use built containers with [`thv run`](./run-mcp-servers.mdx) for local
development
-- Deploy pre-built containers to [Kubernetes](../guides-k8s/run-mcp-k8s.md)
+- Deploy pre-built containers to [Kubernetes](../guides-k8s/run-mcp-k8s.mdx)
- Set up [CI/CD pipelines](#cicd-integration) for automated building
- Learn about [container registry workflows](#custom-image-tagging)
@@ -324,7 +324,7 @@ thv build --tag my-server:dev go:///path/to/my-project
- [`thv build` command reference](../reference/cli/thv_build.md)
- [Run MCP servers](./run-mcp-servers.mdx)
-- [Run MCP servers in Kubernetes](../guides-k8s/run-mcp-k8s.md)
+- [Run MCP servers in Kubernetes](../guides-k8s/run-mcp-k8s.mdx)
- [Custom permissions](./custom-permissions.mdx)
## Troubleshooting
diff --git a/docs/toolhive/guides-k8s/deploy-operator-helm.md b/docs/toolhive/guides-k8s/deploy-operator-helm.md
index 6c0ef88f..084b0578 100644
--- a/docs/toolhive/guides-k8s/deploy-operator-helm.md
+++ b/docs/toolhive/guides-k8s/deploy-operator-helm.md
@@ -251,9 +251,9 @@ create it.
## Next steps
-See [Run MCP servers in Kubernetes](./run-mcp-k8s.md) to learn how to create and
-manage MCP servers using the ToolHive operator in your Kubernetes cluster. The
-operator supports deploying MCPServer resources based on the deployment mode
+See [Run MCP servers in Kubernetes](./run-mcp-k8s.mdx) to learn how to create
+and manage MCP servers using the ToolHive operator in your Kubernetes cluster.
+The operator supports deploying MCPServer resources based on the deployment mode
configured during installation.
## Related information
diff --git a/docs/toolhive/guides-k8s/intro.md b/docs/toolhive/guides-k8s/intro.md
index 50e593bc..2bcb6d37 100644
--- a/docs/toolhive/guides-k8s/intro.md
+++ b/docs/toolhive/guides-k8s/intro.md
@@ -57,4 +57,4 @@ Kubernetes cluster. Helm simplifies the installation process and lets you manage
the operator using Helm charts.
Once the operator is installed, you can create and manage MCP servers using the
-[`MCPServer` custom resource](./run-mcp-k8s.md).
+[`MCPServer` custom resource](./run-mcp-k8s.mdx).
diff --git a/docs/toolhive/guides-mcp/filesystem.mdx b/docs/toolhive/guides-mcp/filesystem.mdx
index 06949859..ebe89ba6 100644
--- a/docs/toolhive/guides-mcp/filesystem.mdx
+++ b/docs/toolhive/guides-mcp/filesystem.mdx
@@ -109,7 +109,7 @@ outbound network access (see the
Create a Kubernetes manifest to deploy the Filesystem MCP server with a
-[persistent volume](../guides-k8s/run-mcp-k8s.md#mount-a-volume).
+[persistent volume](../guides-k8s/run-mcp-k8s.mdx#mount-a-volume).
Update the `podTemplateSpec` section to include your specific volume claim and
mount path:
diff --git a/docs/toolhive/tutorials/quickstart-k8s.mdx b/docs/toolhive/tutorials/quickstart-k8s.mdx
index 86304040..405e30bb 100644
--- a/docs/toolhive/tutorials/quickstart-k8s.mdx
+++ b/docs/toolhive/tutorials/quickstart-k8s.mdx
@@ -432,8 +432,9 @@ operator.
Here are some next steps to explore:
-- Learn about [advanced MCP server configurations](../guides-k8s/run-mcp-k8s.md)
- for production deployments
+- Learn about
+ [advanced MCP server configurations](../guides-k8s/run-mcp-k8s.mdx) for
+ production deployments
- Learn more about
[Helm deployment options](../guides-k8s/deploy-operator-helm.md) and
configuration
From f9e694e8fb6a00315e9017b3ab1b633846fc6d93 Mon Sep 17 00:00:00 2001
From: Dan Barr <6922515+danbarr@users.noreply.github.com>
Date: Wed, 10 Sep 2025 10:26:06 -0400
Subject: [PATCH 4/4] Update wording, rewrite the Vault section
Signed-off-by: Dan Barr <6922515+danbarr@users.noreply.github.com>
---
docs/toolhive/guides-k8s/run-mcp-k8s.mdx | 148 +++++++++--------------
1 file changed, 56 insertions(+), 92 deletions(-)
diff --git a/docs/toolhive/guides-k8s/run-mcp-k8s.mdx b/docs/toolhive/guides-k8s/run-mcp-k8s.mdx
index 2c659919..f274977b 100644
--- a/docs/toolhive/guides-k8s/run-mcp-k8s.mdx
+++ b/docs/toolhive/guides-k8s/run-mcp-k8s.mdx
@@ -253,14 +253,25 @@ process.
### Run a server with secrets
-For MCP servers that require authentication tokens or other secrets, you can use
-secrets from multiple secrets managers:
+When your MCP servers require authentication tokens or other secrets, ToolHive
+supports multiple secrets management methods to fit your existing
+infrastructure. Choose the method that best suits your needs:
-
+
-This example shows how to use an existing Kubernetes secret to pass a GitHub
-personal access token to the `github` MCP server.
+ToolHive can reference existing Kubernetes secrets to inject sensitive data into
+your MCP server pods as environment variables. This example demonstrates how to
+pass a GitHub personal access token to the `github` MCP server.
+
+First, create the secret. The secret must exist in the same namespace as your
+MCP server and the key must match what you specify in the `MCPServer` resource.
+
+```bash
+kubectl -n production create secret generic github-token --from-literal=token=
+```
+
+Next, define the `MCPServer` resource to reference the secret:
```yaml {13-16} title="my-mcpserver-with-secrets.yaml"
apiVersion: toolhive.stacklok.dev/v1alpha1
@@ -281,15 +292,7 @@ spec:
targetEnvName: GITHUB_PERSONAL_ACCESS_TOKEN
```
-First, create the secret. Note that the secret must be created in the same
-namespace as the MCP server and the key must match the one specified in the
-`MCPServer` resource.
-
-```bash
-kubectl -n production create secret generic github-token --from-literal=token=
-```
-
-Apply the MCPServer resource:
+Finally, apply the MCPServer resource:
```bash
kubectl apply -f my-mcpserver-with-secrets.yaml
@@ -298,18 +301,27 @@ kubectl apply -f my-mcpserver-with-secrets.yaml
-This example shows how to use an existing Kubernetes secret created by the
-[External Secrets Operator](https://external-secrets.io/) to pass a GitHub
-personal access token to the `github` MCP server.
+[External Secrets Operator](https://external-secrets.io/) is a Kubernetes
+operator that integrates external secret management systems and syncs secrets
+into Kubernetes as native resources. This example demonstrates how to use
+ESO-managed secrets with your MCP server.
-:::info[Important]
+:::note
-Given the External Secrets Operator creates standard Kubernetes secrets based on
-external secrets, the MCP server definition will look the same as the Kubernetes
-example.
+When you use the External Secrets Operator, your MCP server definition will look
+the same as the Kubernetes-native example. This is because the External Secrets
+Operator creates standard Kubernetes secrets from external sources.
:::
+First, create a secret using the
+[ExternalSecret resource](https://external-secrets.io/latest/api/externalsecret/).
+The exact configuration depends on your external secret management system. The
+secret must exist in the same namespace as your MCP server and the key must
+match what you specify in the `MCPServer` resource.
+
+Next, define the `MCPServer` resource to reference the secret:
+
```yaml {13-16} title="my-mcpserver-with-secrets-eso.yaml"
apiVersion: toolhive.stacklok.dev/v1alpha1
kind: MCPServer
@@ -329,83 +341,35 @@ spec:
targetEnvName: GITHUB_PERSONAL_ACCESS_TOKEN
```
-First, create the secret by using
-[External Secrets Operator](https://external-secrets.io/latest/api/externalsecret).
-Note that the secret must be created in the same namespace as the MCP server and
-the key must match the one specified in the `MCPServer` resource.
-
-Apply the MCPServer resource:
+Finally, apply the MCPServer resource:
```bash
kubectl apply -f my-mcpserver-with-secrets-eso.yaml
```
-
-
-This example shows how to use [Vault](https://developer.hashicorp.com/vault) to
-inject secrets into the ToolHive containers for consumption.
-
-Injecting secrets using Vault is done with its agent sidecar container, but
-before you can start injecting secrets into the container there are some steps
-to do before hand. This includes setting up Vault to be able to authenticate and
-pull the necessary secrets. We will not detail here how to do this as there are
-some very helpful
-[Vault guides](https://developer.hashicorp.com/vault/tutorials/kubernetes/kubernetes-sidecar)
-on setting this up, but before we can inject secrets into the ToolHive
-containers we need to have the following:
-
-- Vault available
-- Vault configured for Kubernetes authentication
-- Vault policy created to be able to read the desired secrets
-- Vault role created that is bound to the ToolHive ProxyRunner Service Account
- in order to enable authentication
-
-```yaml {23-33} title="my-mcpserver-with-vault-secrets-injection.yaml"
-apiVersion: toolhive.stacklok.dev/v1alpha1
-kind: MCPServer
-metadata:
- name: github-vault-generic
- namespace: toolhive-system
-spec:
- image: ghcr.io/github/github-mcp-server:latest
- transport: stdio
- port: 9095
- permissionProfile:
- type: builtin
- name: network
- resources:
- limits:
- cpu: '100m'
- memory: '128Mi'
- requests:
- cpu: '50m'
- memory: '64Mi'
- resourceOverrides:
- proxyDeployment:
- podTemplateMetadataOverrides:
- annotations:
- # Enable Vault Agent injection
- vault.hashicorp.com/agent-inject: 'true'
- vault.hashicorp.com/role: ''
-
- # Inject GitHub configuration secret
- vault.hashicorp.com/agent-inject-secret-github-config: 'workload-secrets/data/github-mcp/config'
- vault.hashicorp.com/agent-inject-template-github-config: |
- {{- with secret "workload-secrets/data/github-mcp/config" -}}
- GITHUB_PERSONAL_ACCESS_TOKEN={{ .Data.data.token }}
- {{- end -}}
-```
-
-Apply the MCPServer resource:
-
-```bash
-kubectl apply -f my-mcpserver-with-vault-secrets-injection.yaml
-```
-
-The Vault agent sidecar will now inject secrets from the
-`workload-secrets/data/github-mcp/config` inside of Vault, into the ProxyRunner
-container.
+
+
+HashiCorp Vault provides multiple integration methods for Kubernetes
+environments:
+
+1. [Vault Sidecar Agent Injector](https://developer.hashicorp.com/vault/docs/deploy/kubernetes/injector),
+ which injects a sidecar container into your pod to fetch and renew secrets
+2. [Vault Secrets Operator](https://developer.hashicorp.com/vault/docs/deploy/kubernetes/vso),
+ which creates Kubernetes secrets from Vault secrets (similar to the External
+ Secrets Operator)
+3. [Vault CSI Provider](https://developer.hashicorp.com/vault/docs/deploy/kubernetes/csi),
+ which mounts secrets directly into your pod as files
+
+ToolHive supports the first two methods. When you use the Vault Secrets
+Operator, your MCP server definition will look the same as the Kubernetes-native
+example because the Vault Secrets Operator creates standard Kubernetes secrets
+from Vault.
+
+The Vault Sidecar Agent Injector requires additional configuration in your
+`MCPServer` resource to add the required annotations. For a complete example,
+see the
+[HashiCorp Vault integration tutorial](../tutorials/vault-integration.mdx).