Skip to content

Commit f9e694e

Browse files
committed
Update wording, rewrite the Vault section
Signed-off-by: Dan Barr <[email protected]>
1 parent 6cb9a4d commit f9e694e

File tree

1 file changed

+56
-92
lines changed

1 file changed

+56
-92
lines changed

docs/toolhive/guides-k8s/run-mcp-k8s.mdx

Lines changed: 56 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -253,14 +253,25 @@ process.
253253

254254
### Run a server with secrets
255255

256-
For MCP servers that require authentication tokens or other secrets, you can use
257-
secrets from multiple secrets managers:
256+
When your MCP servers require authentication tokens or other secrets, ToolHive
257+
supports multiple secrets management methods to fit your existing
258+
infrastructure. Choose the method that best suits your needs:
258259

259260
<Tabs groupId='secret-manager' queryString='secret-manager'>
260-
<TabItem value='kubernetes-native' label='Kubernetes' default>
261+
<TabItem value='kubernetes-native' label='Kubernetes secrets' default>
261262

262-
This example shows how to use an existing Kubernetes secret to pass a GitHub
263-
personal access token to the `github` MCP server.
263+
ToolHive can reference existing Kubernetes secrets to inject sensitive data into
264+
your MCP server pods as environment variables. This example demonstrates how to
265+
pass a GitHub personal access token to the `github` MCP server.
266+
267+
First, create the secret. The secret must exist in the same namespace as your
268+
MCP server and the key must match what you specify in the `MCPServer` resource.
269+
270+
```bash
271+
kubectl -n production create secret generic github-token --from-literal=token=<YOUR_TOKEN>
272+
```
273+
274+
Next, define the `MCPServer` resource to reference the secret:
264275

265276
```yaml {13-16} title="my-mcpserver-with-secrets.yaml"
266277
apiVersion: toolhive.stacklok.dev/v1alpha1
@@ -281,15 +292,7 @@ spec:
281292
targetEnvName: GITHUB_PERSONAL_ACCESS_TOKEN
282293
```
283294

284-
First, create the secret. Note that the secret must be created in the same
285-
namespace as the MCP server and the key must match the one specified in the
286-
`MCPServer` resource.
287-
288-
```bash
289-
kubectl -n production create secret generic github-token --from-literal=token=<YOUR_TOKEN>
290-
```
291-
292-
Apply the MCPServer resource:
295+
Finally, apply the MCPServer resource:
293296

294297
```bash
295298
kubectl apply -f my-mcpserver-with-secrets.yaml
@@ -298,18 +301,27 @@ kubectl apply -f my-mcpserver-with-secrets.yaml
298301
</TabItem>
299302
<TabItem value='eso' label='External Secrets Operator'>
300303

301-
This example shows how to use an existing Kubernetes secret created by the
302-
[External Secrets Operator](https://external-secrets.io/) to pass a GitHub
303-
personal access token to the `github` MCP server.
304+
[External Secrets Operator](https://external-secrets.io/) is a Kubernetes
305+
operator that integrates external secret management systems and syncs secrets
306+
into Kubernetes as native resources. This example demonstrates how to use
307+
ESO-managed secrets with your MCP server.
304308

305-
:::info[Important]
309+
:::note
306310

307-
Given the External Secrets Operator creates standard Kubernetes secrets based on
308-
external secrets, the MCP server definition will look the same as the Kubernetes
309-
example.
311+
When you use the External Secrets Operator, your MCP server definition will look
312+
the same as the Kubernetes-native example. This is because the External Secrets
313+
Operator creates standard Kubernetes secrets from external sources.
310314

311315
:::
312316

317+
First, create a secret using the
318+
[ExternalSecret resource](https://external-secrets.io/latest/api/externalsecret/).
319+
The exact configuration depends on your external secret management system. The
320+
secret must exist in the same namespace as your MCP server and the key must
321+
match what you specify in the `MCPServer` resource.
322+
323+
Next, define the `MCPServer` resource to reference the secret:
324+
313325
```yaml {13-16} title="my-mcpserver-with-secrets-eso.yaml"
314326
apiVersion: toolhive.stacklok.dev/v1alpha1
315327
kind: MCPServer
@@ -329,83 +341,35 @@ spec:
329341
targetEnvName: GITHUB_PERSONAL_ACCESS_TOKEN
330342
```
331343

332-
First, create the secret by using
333-
[External Secrets Operator](https://external-secrets.io/latest/api/externalsecret).
334-
Note that the secret must be created in the same namespace as the MCP server and
335-
the key must match the one specified in the `MCPServer` resource.
336-
337-
Apply the MCPServer resource:
344+
Finally, apply the MCPServer resource:
338345

339346
```bash
340347
kubectl apply -f my-mcpserver-with-secrets-eso.yaml
341348
```
342349

343350
</TabItem>
344-
<TabItem value='vault' label='Vault Secret Injection'>
345-
346-
This example shows how to use [Vault](https://developer.hashicorp.com/vault) to
347-
inject secrets into the ToolHive containers for consumption.
348-
349-
Injecting secrets using Vault is done with its agent sidecar container, but
350-
before you can start injecting secrets into the container there are some steps
351-
to do before hand. This includes setting up Vault to be able to authenticate and
352-
pull the necessary secrets. We will not detail here how to do this as there are
353-
some very helpful
354-
[Vault guides](https://developer.hashicorp.com/vault/tutorials/kubernetes/kubernetes-sidecar)
355-
on setting this up, but before we can inject secrets into the ToolHive
356-
containers we need to have the following:
357-
358-
- Vault available
359-
- Vault configured for Kubernetes authentication
360-
- Vault policy created to be able to read the desired secrets
361-
- Vault role created that is bound to the ToolHive ProxyRunner Service Account
362-
in order to enable authentication
363-
364-
```yaml {23-33} title="my-mcpserver-with-vault-secrets-injection.yaml"
365-
apiVersion: toolhive.stacklok.dev/v1alpha1
366-
kind: MCPServer
367-
metadata:
368-
name: github-vault-generic
369-
namespace: toolhive-system
370-
spec:
371-
image: ghcr.io/github/github-mcp-server:latest
372-
transport: stdio
373-
port: 9095
374-
permissionProfile:
375-
type: builtin
376-
name: network
377-
resources:
378-
limits:
379-
cpu: '100m'
380-
memory: '128Mi'
381-
requests:
382-
cpu: '50m'
383-
memory: '64Mi'
384-
resourceOverrides:
385-
proxyDeployment:
386-
podTemplateMetadataOverrides:
387-
annotations:
388-
# Enable Vault Agent injection
389-
vault.hashicorp.com/agent-inject: 'true'
390-
vault.hashicorp.com/role: '<ROLE_NAME_CREATE_IN_VAULT>'
391-
392-
# Inject GitHub configuration secret
393-
vault.hashicorp.com/agent-inject-secret-github-config: 'workload-secrets/data/github-mcp/config'
394-
vault.hashicorp.com/agent-inject-template-github-config: |
395-
{{- with secret "workload-secrets/data/github-mcp/config" -}}
396-
GITHUB_PERSONAL_ACCESS_TOKEN={{ .Data.data.token }}
397-
{{- end -}}
398-
```
399-
400-
Apply the MCPServer resource:
401-
402-
```bash
403-
kubectl apply -f my-mcpserver-with-vault-secrets-injection.yaml
404-
```
405-
406-
The Vault agent sidecar will now inject secrets from the
407-
`workload-secrets/data/github-mcp/config` inside of Vault, into the ProxyRunner
408-
container.
351+
<TabItem value='vault' label='HashiCorp Vault'>
352+
353+
HashiCorp Vault provides multiple integration methods for Kubernetes
354+
environments:
355+
356+
1. [Vault Sidecar Agent Injector](https://developer.hashicorp.com/vault/docs/deploy/kubernetes/injector),
357+
which injects a sidecar container into your pod to fetch and renew secrets
358+
2. [Vault Secrets Operator](https://developer.hashicorp.com/vault/docs/deploy/kubernetes/vso),
359+
which creates Kubernetes secrets from Vault secrets (similar to the External
360+
Secrets Operator)
361+
3. [Vault CSI Provider](https://developer.hashicorp.com/vault/docs/deploy/kubernetes/csi),
362+
which mounts secrets directly into your pod as files
363+
364+
ToolHive supports the first two methods. When you use the Vault Secrets
365+
Operator, your MCP server definition will look the same as the Kubernetes-native
366+
example because the Vault Secrets Operator creates standard Kubernetes secrets
367+
from Vault.
368+
369+
The Vault Sidecar Agent Injector requires additional configuration in your
370+
`MCPServer` resource to add the required annotations. For a complete example,
371+
see the
372+
[HashiCorp Vault integration tutorial](../tutorials/vault-integration.mdx).
409373

410374
</TabItem>
411375
</Tabs>

0 commit comments

Comments
 (0)