Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/upstream-projects.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ projects:

- id: toolhive
repo: stacklok/toolhive
version: v0.22.0
version: v0.23.1
# toolhive is a monorepo covering the CLI, the Kubernetes
# operator, and the vMCP gateway. It also introduces cross-
# cutting features that land in concepts/, integrations/,
Expand Down
4 changes: 2 additions & 2 deletions docs/toolhive/guides-cli/build-containers.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ thv build --tag mcp-servers/git-server:stable uvx://mcp-server-git
Use the built image in your Kubernetes manifests:

```yaml
apiVersion: toolhive.stacklok.dev/v1alpha1
apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPServer
metadata:
name: git-server
Expand Down Expand Up @@ -263,7 +263,7 @@ you need to pre-build containers before deploying them.
3. **Deploy to Kubernetes** using the pre-built image:

```yaml
apiVersion: toolhive.stacklok.dev/v1alpha1
apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPServer
metadata:
name: git-server
Expand Down
71 changes: 58 additions & 13 deletions docs/toolhive/guides-k8s/auth-k8s.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ isolation.
<TabItem value="inline" label="External IdP" default>

```yaml title="shared-oidc-config.yaml"
apiVersion: toolhive.stacklok.dev/v1alpha1
apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPOIDCConfig
metadata:
name: production-oidc
Expand All @@ -127,7 +127,7 @@ spec:
<TabItem value="k8s" label="Kubernetes service account">

```yaml title="k8s-oidc-config.yaml"
apiVersion: toolhive.stacklok.dev/v1alpha1
apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPOIDCConfig
metadata:
name: k8s-sa-oidc
Expand All @@ -154,7 +154,7 @@ Use `oidcConfigRef` instead of inline `oidcConfig`. Each server must set a
unique `audience` to prevent token replay across servers:

```yaml title="mcp-server-shared-oidc.yaml"
apiVersion: toolhive.stacklok.dev/v1alpha1
apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPServer
metadata:
name: weather-server
Expand Down Expand Up @@ -217,7 +217,7 @@ settings, and an `MCPServer` resource that references it. The ToolHive proxy
handles authentication before forwarding requests to the MCP server.

```yaml title="mcp-server-external-auth.yaml"
apiVersion: toolhive.stacklok.dev/v1alpha1
apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPOIDCConfig
metadata:
name: external-oidc
Expand All @@ -229,7 +229,7 @@ spec:
clientId: 'your-client-id'
jwksUrl: 'https://your-oidc-issuer.com/path/to/jwks'
---
apiVersion: toolhive.stacklok.dev/v1alpha1
apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPServer
metadata:
name: weather-server-external
Expand Down Expand Up @@ -310,7 +310,7 @@ Create an `MCPOIDCConfig` resource for Kubernetes service account authentication
and an `MCPServer` that references it:

```yaml title="mcp-server-k8s-auth.yaml"
apiVersion: toolhive.stacklok.dev/v1alpha1
apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPOIDCConfig
metadata:
name: k8s-sa-oidc
Expand All @@ -321,7 +321,7 @@ spec:
serviceAccount: 'mcp-client'
namespace: 'client-apps'
---
apiVersion: toolhive.stacklok.dev/v1alpha1
apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPServer
metadata:
name: weather-server-k8s
Expand Down Expand Up @@ -499,7 +499,7 @@ Create an `MCPExternalAuthConfig` resource with the `embeddedAuthServer` type.
This example configures an OIDC upstream provider (the most common case):

```yaml title="embedded-auth-config.yaml"
apiVersion: toolhive.stacklok.dev/v1alpha1
apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPExternalAuthConfig
metadata:
name: embedded-auth-server
Expand Down Expand Up @@ -562,7 +562,7 @@ authorization server itself. The MCPOIDCConfig issuer must match the `issuer` in
your `MCPExternalAuthConfig`.

```yaml title="mcp-server-embedded-auth.yaml"
apiVersion: toolhive.stacklok.dev/v1alpha1
apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPOIDCConfig
metadata:
name: embedded-auth-oidc
Expand All @@ -573,7 +573,7 @@ spec:
# This must match the embedded authorization server issuer url
issuer: 'https://mcp.example.com'
---
apiVersion: toolhive.stacklok.dev/v1alpha1
apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPServer
metadata:
name: weather-server-embedded
Expand Down Expand Up @@ -690,7 +690,7 @@ for providers like GitHub that use OAuth 2.0 but don't implement the full OIDC
specification.

```yaml title="embedded-auth-oauth2-config.yaml"
apiVersion: toolhive.stacklok.dev/v1alpha1
apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPExternalAuthConfig
metadata:
name: embedded-auth-oauth2
Expand Down Expand Up @@ -788,6 +788,51 @@ refresh-token state), add `prompt: 'consent'` alongside `access_type: 'offline'`
- Google then shows the consent screen on every login and re-issues a refresh
token each time.

### Default callback URL for upstream providers

When you omit `redirectUri` from an upstream provider's `oidcConfig` or
`oauth2Config`, the operator defaults it to `{resourceUrl}/oauth/callback`.
`resourceUrl` is the `oidcConfigRef.resourceUrl` set on the MCPServer or
VirtualMCPServer that references this MCPExternalAuthConfig. It's typically the
external URL that MCP clients use to reach the server.

You still need to register this callback URL with your upstream OAuth2 or OIDC
provider before the flow can complete. Use the same URL on both sides: the value
computed from `resourceUrl` here, and the authorized redirect URI in your
provider's application settings.

For example, given this `oidcConfigRef` on an MCPServer:

```yaml
spec:
oidcConfigRef:
name: embedded-auth-oidc
audience: 'https://mcp.example.com/mcp'
resourceUrl: 'https://mcp.example.com/mcp'
```

Omitting `redirectUri` on the upstream provider resolves the callback to
`https://mcp.example.com/mcp/oauth/callback`:

```yaml
upstreamProviders:
- name: google
type: oidc
oidcConfig:
issuerUrl: 'https://accounts.google.com'
clientId: '<YOUR_GOOGLE_CLIENT_ID>'
clientSecretRef:
name: upstream-idp-secret
key: client-secret
# redirectUri omitted - defaults to:
# https://mcp.example.com/mcp/oauth/callback
```

Set `redirectUri` explicitly if you need a non-default callback path, for
example to route the callback through a separate gateway hostname. If
`resourceUrl` is also unset, no default is applied and the upstream provider
must have `redirectUri` set explicitly.

## Set up authorization

All authentication approaches can use the same authorization configuration using
Expand Down Expand Up @@ -836,7 +881,7 @@ kubectl apply -f authz-configmap.yaml
Add the authorization configuration to your `MCPServer` resources:

```yaml title="mcp-server-with-authz.yaml"
apiVersion: toolhive.stacklok.dev/v1alpha1
apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPOIDCConfig
metadata:
name: k8s-sa-authz-oidc
Expand All @@ -847,7 +892,7 @@ spec:
serviceAccount: 'mcp-client'
namespace: 'client-apps'
---
apiVersion: toolhive.stacklok.dev/v1alpha1
apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPServer
metadata:
name: weather-server-with-authz
Expand Down
6 changes: 3 additions & 3 deletions docs/toolhive/guides-k8s/connect-clients.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ First, ensure you have an MCP server deployed. This example uses the `fetch`
server:

```yaml title="fetch-server.yaml"
apiVersion: toolhive.stacklok.dev/v1alpha1
apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPServer
metadata:
name: fetch
Expand Down Expand Up @@ -235,7 +235,7 @@ First, in the MCPServer spec for each server, ensure the `resourceUrl` property
is set to the full client-facing URL via `oidcConfigRef`:

```yaml title="fetch-server-oauth.yaml"
apiVersion: toolhive.stacklok.dev/v1alpha1
apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPServer
# ...
spec:
Expand Down Expand Up @@ -493,7 +493,7 @@ First, in the MCPServer spec for each server, ensure the `resourceUrl` property
is set to the full client-facing URL via `oidcConfigRef`:

```yaml title="fetch-server-oauth.yaml"
apiVersion: toolhive.stacklok.dev/v1alpha1
apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPServer
# ...
spec:
Expand Down
16 changes: 8 additions & 8 deletions docs/toolhive/guides-k8s/customize-tools.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ descriptions. You reference the configuration from an MCPServer using the
This example exposes only three tools on a server:

```yaml title="toolconfig-basic.yaml"
apiVersion: toolhive.stacklok.dev/v1alpha1
apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPToolConfig
metadata:
name: basic-tool-filter
Expand Down Expand Up @@ -51,7 +51,7 @@ scopes (for example, separate GitHub orgs, repos, or environments). Renaming
tools makes intent obvious and helps prevent mistakes.

```yaml title="toolconfig-with-overrides.yaml"
apiVersion: toolhive.stacklok.dev/v1alpha1
apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPToolConfig
metadata:
name: github-tools-config
Expand Down Expand Up @@ -112,7 +112,7 @@ resource.
<TabItem value="mcpserver" label="MCPServer" default>

```yaml {10-11} title="mcpserver-with-toolconfig.yaml"
apiVersion: toolhive.stacklok.dev/v1alpha1
apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPServer
metadata:
name: github
Expand All @@ -130,7 +130,7 @@ spec:
<TabItem value="mcpremoteproxy" label="MCPRemoteProxy">

```yaml {10-11} title="mcpremoteproxy-with-toolconfig.yaml"
apiVersion: toolhive.stacklok.dev/v1alpha1
apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPRemoteProxy
metadata:
name: github
Expand Down Expand Up @@ -161,7 +161,7 @@ Run the GitHub MCP twice, once per organization, and rename tools so intent is
clear to clients.

```yaml title="github-org-scoped-tools.yaml"
apiVersion: toolhive.stacklok.dev/v1alpha1
apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPToolConfig
metadata:
name: github-acme-tools
Expand All @@ -176,7 +176,7 @@ spec:
get_pull_request:
name: github_acme_get_pr
---
apiVersion: toolhive.stacklok.dev/v1alpha1
apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPToolConfig
metadata:
name: github-foocorp-tools
Expand All @@ -191,7 +191,7 @@ spec:
get_pull_request:
name: github_foocorp_get_pr
---
apiVersion: toolhive.stacklok.dev/v1alpha1
apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPServer
metadata:
name: github-acme
Expand All @@ -204,7 +204,7 @@ spec:
toolConfigRef:
name: github-acme-tools
---
apiVersion: toolhive.stacklok.dev/v1alpha1
apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPServer
metadata:
name: github-foocorp
Expand Down
6 changes: 3 additions & 3 deletions docs/toolhive/guides-k8s/logging.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ your MCP server manifest:
<TabItem value="mcpserver" label="MCPServer" default>

```yaml {11-12}
apiVersion: toolhive.stacklok.dev/v1alpha1
apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPServer
metadata:
name: <SERVER_NAME>
Expand All @@ -102,7 +102,7 @@ spec:
<TabItem value="mcpremoteproxy" label="MCPRemoteProxy">

```yaml {11-12}
apiVersion: toolhive.stacklok.dev/v1alpha1
apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPRemoteProxy
metadata:
name: <SERVER_NAME>
Expand All @@ -120,7 +120,7 @@ spec:
<TabItem value="virtualmcpserver" label="VirtualMCPServer">

```yaml {11-14}
apiVersion: toolhive.stacklok.dev/v1alpha1
apiVersion: toolhive.stacklok.dev/v1beta1
kind: VirtualMCPServer
metadata:
name: <SERVER_NAME>
Expand Down
Loading