Skip to content

Commit d44013d

Browse files
danbarrJAORMX
authored andcommitted
Polish vMCP docs (#347)
* Polish vMCP documentation - Apply consistent terminology: 'Virtual MCP Server (vMCP)' on first mention, then 'vMCP' - Rewrite bullet lists with complete sentences - Add MCPGroup context explanation on first use - Expand outgoing auth configuration details - Enhance experimental feature warning - Improve language directness * Add vMCP usage to style guide and LLM instructions * Note that vMCP is part of the operator * Add vMCP to nav menu * Polish the intro * Polish the config guide - Add MCPGroup section since it doesn't have its own guide - Remove redundant auth content, just point to auth guide - Note that ClusterIP can be exposed via Ingress/Gateway * Add vMCP CRDs to operator deployment guide * Rename vMCP concepts file and re-order guides Feels like the tool aggregation and composite guides logically belong together. * Polish auth guide * Polish tool aggregation guide * Polish composite tools guide - Soften technical jargon ("DAG") - Add basic info up front before the full use cases - Make sure all YAML snippets have parent keys to make location and indentation clear * Polish the quickstart and concepts guides * Add quickstart and concepts links to index * Clarify inbound auth spec conformance * Clarify service options --------- Signed-off-by: Dan Barr <[email protected]> Co-authored-by: Dan Barr <[email protected]>
1 parent 2399a89 commit d44013d

File tree

14 files changed

+471
-355
lines changed

14 files changed

+471
-355
lines changed

.github/copilot-instructions.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ Common terms used in this project:
107107
- open source (not "open-source")
108108
- large language model (LLM)
109109
- Visual Studio Code ("VS Code" after first use)
110+
- Virtual MCP Server (vMCP) - a feature of ToolHive that aggregates multiple MCP servers into a single endpoint; use "Virtual MCP Server (vMCP)" on first use, "vMCP" thereafter
110111

111112
Check this list for consistent use within the documentation. If you find inconsistencies, update the text to match the preferred term. If you find a term that is not listed here, consider adding it to the list for future reference.
112113

AGENTS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ Common terms used in this project:
107107
- open source (not "open-source")
108108
- large language model (LLM)
109109
- Visual Studio Code ("VS Code" after first use)
110+
- Virtual MCP Server (vMCP) - a feature of ToolHive that aggregates multiple MCP servers into a single endpoint; use "Virtual MCP Server (vMCP)" on first use, "vMCP" thereafter
110111

111112
Check this list for consistent use within the documentation. If you find inconsistencies, update the text to match the preferred term. If you find a term that is not listed here, consider adding it to the list for future reference.
112113

STYLE-GUIDE.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,11 @@ all caps. Written out, it is lower-cased.
263263
applications provide context to LLMs. MCP is an abbreviation, so it's written in
264264
all caps. Written out, it is proper-cased.
265265

266+
**vMCP**: Virtual MCP Server, a feature of ToolHive that aggregates multiple MCP
267+
servers into a single endpoint. It's written with a lowercase "v" followed by
268+
"MC" in all caps and a capital "P" (not "VMCP" or "Vmcp"). Use "Virtual MCP
269+
Server (vMCP)" on first use, "vMCP" thereafter.
270+
266271
**npm**: the registry for JavaScript packages (the "npm registry"), and the
267272
default package manager for JavaScript. Since it's both the registry _and_ the
268273
package manager, it may be useful to disambiguate "the npm registry". It's not

docs/toolhive/concepts/vmcp-architecture.mdx renamed to docs/toolhive/concepts/vmcp.mdx

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
---
22
title: Understanding Virtual MCP Server
3+
sidebar_label: Virtual MCP Server (vMCP)
34
description:
45
Learn what Virtual MCP Server does, why it exists, and when to use it.
56
---
67

7-
This document explains Virtual MCP Server (vMCP), why it exists, and when you
8-
should use it. You'll learn how vMCP simplifies managing multiple MCP servers
9-
and enables powerful multi-system workflows.
8+
This document explains Virtual MCP Server (vMCP), a feature of the ToolHive
9+
Kubernetes Operator. You'll learn why it exists, when to use it, and how it
10+
simplifies managing multiple MCP servers while enabling powerful multi-system
11+
workflows.
1012

1113
## The problem vMCP solves
1214

@@ -20,7 +22,7 @@ tools with sensible defaults.
2022

2123
## Core value propositions
2224

23-
Virtual MCP Server delivers four key benefits:
25+
vMCP delivers four key benefits:
2426

2527
1. **Reduce complexity**: Many connections become one, dramatically simplifying
2628
configuration
@@ -39,8 +41,8 @@ own configuration, authentication, and maintenance. vMCP aggregates all backends
3941
into one endpoint with automatic conflict resolution.
4042

4143
**Example scenario**: An engineering team needs access to 8 backend servers
42-
(GitHub, Jira, Slack, Confluence, PagerDuty, Datadog, AWS, Internal Docs).
43-
Instead of configuring 8 separate connections, they configure one vMCP
44+
(GitHub, Jira, Slack, Confluence, PagerDuty, Datadog, AWS, and internal company
45+
docs). Instead of configuring 8 separate connections, they configure one vMCP
4446
connection with SSO. This significantly reduces configuration complexity and
4547
makes onboarding new team members much easier.
4648

@@ -57,14 +59,15 @@ error handling, and human-in-the-loop approval gates.
5759

5860
**Example scenario**: During an incident investigation, you need logs from your
5961
logging system, metrics from your monitoring platform, traces from your tracing
60-
service, and infrastructure status from your cloud provider. With vMCP, you
61-
fetch all of this in parallel (4x faster than sequential), automatically
62-
aggregate it into a formatted report, and create a Jira ticket with all the
63-
data. This workflow is reusable for every incident.
64-
65-
**Example scenario**: For a PR deployment, you might want to merge the PR, wait
66-
for tests, ask a human for approval, deploy only if approved, and notify Slack.
67-
vMCP handles this entire flow declaratively, with automatic rollback on
62+
service, and infrastructure status from your cloud provider. Without vMCP, an
63+
engineer manually runs 4 commands sequentially and aggregates results. With
64+
vMCP, you fetch all of this in parallel, automatically aggregate it into a
65+
formatted report, and create a Jira ticket with all the data. This workflow is
66+
reusable for every incident.
67+
68+
**Example scenario**: For an app deployment, merge the pull request, wait for
69+
tests, ask a human for approval, deploy only if approved, and notify the team in
70+
Slack. vMCP handles this entire flow declaratively, with automatic rollback on
6871
deployment failure.
6972

7073
### Tool customization and overrides
@@ -88,24 +91,26 @@ Generic servers require repetitive parameter specification. You always use the
8891
same repo, channel, or database. vMCP lets you create specialized instances with
8992
pre-configured defaults.
9093

91-
**Example scenario**: All GitHub queries for your team should default to the
92-
`stacklok/toolhive` repo. Engineers never need to specify the repo parameter,
93-
and they can't accidentally query the wrong repository.
94+
**Example scenario**: Without vMCP, every GitHub query requires specifying
95+
`repo: stacklok/toolhive`. With vMCP, you pre-configure this default - engineers
96+
never specify the repo parameter, and they can't accidentally query the wrong
97+
repository. This eliminates hundreds of repetitive parameter entries per week.
9498

95-
**Example scenario**: Staging database is the default (safe for development),
96-
while production queries require an explicit approval gate. Connection details
97-
are centralized in the vMCP configuration.
99+
**Example scenario**: Configure staging database as the default (safe for
100+
development), while production queries require an explicit approval gate.
101+
Connection details are centralized in vMCP configuration instead of scattered
102+
across individual tool configurations.
98103

99104
### Authentication boundary separation
100105

101106
Different auth is needed for clients versus backends, and managing credentials
102107
across multiple systems is complex. vMCP implements a two-boundary auth model
103108
that separates these concerns.
104109

105-
**How it works**: Clients authenticate to vMCP using the mechanism defined in
106-
the MCP specification. vMCP then handles authentication to each backend MCP
107-
server independently. Revoking access is simple: disable the user in your
108-
identity provider and all backend access is revoked instantly.
110+
**How it works**: Clients authenticate to vMCP using OAuth 2.1 authorization as
111+
defined in the MCP specification. vMCP then handles authentication to each
112+
backend MCP server independently. Revoking access is simple: disable the user in
113+
your identity provider and all backend access is revoked instantly.
109114

110115
This approach provides single sign-on for users, centralized access control, and
111116
a complete audit trail.
@@ -128,14 +133,13 @@ a complete audit trail.
128133

129134
## Summary
130135

131-
Virtual MCP Server transforms MCP from individual servers into a unified
132-
orchestration platform. The use cases range from simple aggregation to complex
133-
workflows with approval gates, making it valuable for teams managing multiple
134-
MCP servers.
136+
vMCP transforms MCP from individual servers into a unified orchestration
137+
platform. The use cases range from simple aggregation to complex workflows with
138+
approval gates, making it valuable for teams managing multiple MCP servers.
135139

136140
## Related information
137141

138-
- [Deploy Virtual MCP Server](../guides-vmcp/intro.mdx)
142+
- [Deploy vMCP](../guides-vmcp/intro.mdx)
143+
- [Configure authentication](../guides-vmcp/authentication.mdx)
139144
- [Tool aggregation and conflict resolution](../guides-vmcp/tool-aggregation.mdx)
140-
- [Authentication](../guides-vmcp/authentication.mdx)
141145
- [Composite tools and workflows](../guides-vmcp/composite-tools.mdx)

docs/toolhive/guides-k8s/deploy-operator-helm.mdx

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ chart. To install a specific version, append `--version <VERSION>` to the
3333
command, for example:
3434

3535
```bash
36-
helm upgrade --install toolhive-operator-crds oci://ghcr.io/stacklok/toolhive/toolhive-operator-crds --version 0.0.52
36+
helm upgrade --install toolhive-operator-crds oci://ghcr.io/stacklok/toolhive/toolhive-operator-crds --version 0.0.73
3737
```
3838

3939
## Install the operator
@@ -52,7 +52,7 @@ chart. To install a specific version, append `--version <VERSION>` to the
5252
command, for example:
5353

5454
```bash
55-
helm upgrade --install toolhive-operator oci://ghcr.io/stacklok/toolhive/toolhive-operator -n toolhive-system --create-namespace --version 0.3.7
55+
helm upgrade --install toolhive-operator oci://ghcr.io/stacklok/toolhive/toolhive-operator -n toolhive-system --create-namespace --version 0.5.6
5656
```
5757

5858
Verify the installation:
@@ -237,21 +237,23 @@ and then apply the CRDs using `kubectl`.
237237
First, upgrade the CRD Helm chart to match your target operator version:
238238

239239
```bash
240-
helm upgrade -i toolhive-operator-crds oci://ghcr.io/stacklok/toolhive/toolhive-operator-crds --version 0.0.52
240+
helm upgrade -i toolhive-operator-crds oci://ghcr.io/stacklok/toolhive/toolhive-operator-crds --version 0.0.73
241241
```
242242

243243
Then apply the CRDs from the same version tag:
244244

245245
```bash
246-
kubectl apply -f https://raw.githubusercontent.com/stacklok/toolhive/refs/tags/toolhive-operator-crds-0.0.52/deploy/charts/operator-crds/crds/toolhive.stacklok.dev_mcpexternalauthconfigs.yaml
247-
kubectl apply -f https://raw.githubusercontent.com/stacklok/toolhive/refs/tags/toolhive-operator-crds-0.0.52/deploy/charts/operator-crds/crds/toolhive.stacklok.dev_mcptoolconfigs.yaml
248-
kubectl apply -f https://raw.githubusercontent.com/stacklok/toolhive/refs/tags/toolhive-operator-crds-0.0.52/deploy/charts/operator-crds/crds/toolhive.stacklok.dev_mcpremoteproxies.yaml
249-
kubectl apply -f https://raw.githubusercontent.com/stacklok/toolhive/refs/tags/toolhive-operator-crds-0.0.52/deploy/charts/operator-crds/crds/toolhive.stacklok.dev_mcpservers.yaml
250-
kubectl apply -f https://raw.githubusercontent.com/stacklok/toolhive/refs/tags/toolhive-operator-crds-0.0.52/deploy/charts/operator-crds/crds/toolhive.stacklok.dev_mcpgroups.yaml
251-
kubectl apply -f https://raw.githubusercontent.com/stacklok/toolhive/refs/tags/toolhive-operator-crds-0.0.52/deploy/charts/operator-crds/crds/toolhive.stacklok.dev_mcpregistries.yaml
246+
kubectl apply -f https://raw.githubusercontent.com/stacklok/toolhive/refs/tags/toolhive-operator-crds-0.0.73/deploy/charts/operator-crds/crds/toolhive.stacklok.dev_mcpexternalauthconfigs.yaml
247+
kubectl apply -f https://raw.githubusercontent.com/stacklok/toolhive/refs/tags/toolhive-operator-crds-0.0.73/deploy/charts/operator-crds/crds/toolhive.stacklok.dev_mcptoolconfigs.yaml
248+
kubectl apply -f https://raw.githubusercontent.com/stacklok/toolhive/refs/tags/toolhive-operator-crds-0.0.73/deploy/charts/operator-crds/crds/toolhive.stacklok.dev_mcpremoteproxies.yaml
249+
kubectl apply -f https://raw.githubusercontent.com/stacklok/toolhive/refs/tags/toolhive-operator-crds-0.0.73/deploy/charts/operator-crds/crds/toolhive.stacklok.dev_mcpservers.yaml
250+
kubectl apply -f https://raw.githubusercontent.com/stacklok/toolhive/refs/tags/toolhive-operator-crds-0.0.73/deploy/charts/operator-crds/crds/toolhive.stacklok.dev_mcpgroups.yaml
251+
kubectl apply -f https://raw.githubusercontent.com/stacklok/toolhive/refs/tags/toolhive-operator-crds-0.0.73/deploy/charts/operator-crds/crds/toolhive.stacklok.dev_mcpregistries.yaml
252+
kubectl apply -f https://raw.githubusercontent.com/stacklok/toolhive/refs/tags/toolhive-operator-crds-0.0.73/deploy/charts/operator-crds/crds/toolhive.stacklok.dev_virtualmcpcompositetooldefinitions.yaml
253+
kubectl apply -f https://raw.githubusercontent.com/stacklok/toolhive/refs/tags/toolhive-operator-crds-0.0.73/deploy/charts/operator-crds/crds/toolhive.stacklok.dev_virtualmcpservers.yaml
252254
```
253255

254-
Replace `0.0.52` in both commands with your target CRD version.
256+
Replace `0.0.73` in both commands with your target CRD version.
255257

256258
### Upgrade the operator Helm release
257259

@@ -267,7 +269,7 @@ This upgrades the operator to the latest version available in the OCI registry.
267269
To upgrade to a specific version, add the `--version` flag:
268270

269271
```bash
270-
helm upgrade -i toolhive-operator oci://ghcr.io/stacklok/toolhive/toolhive-operator -n toolhive-system --reuse-values --version 0.3.7
272+
helm upgrade -i toolhive-operator oci://ghcr.io/stacklok/toolhive/toolhive-operator -n toolhive-system --reuse-values --version 0.5.6
271273
```
272274

273275
If you have a custom `values.yaml` file, include it with the `-f` flag:
@@ -302,6 +304,8 @@ kubectl delete crd mcpremoteproxies.toolhive.stacklok.dev
302304
kubectl delete crd mcpservers.toolhive.stacklok.dev
303305
kubectl delete crd mcpgroups.toolhive.stacklok.dev
304306
kubectl delete crd mcpregistries.toolhive.stacklok.dev
307+
kubectl delete crd virtualmcpcompositetooldefinitions.toolhive.stacklok.dev
308+
kubectl delete crd virtualmcpservers.toolhive.stacklok.dev
305309
```
306310

307311
Finally, uninstall the CRD Helm chart metadata:

docs/toolhive/guides-vmcp/authentication.mdx

Lines changed: 36 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
---
22
title: Authentication
3-
description: Configure client and backend authentication for Virtual MCP Server.
3+
description: Configure client and backend authentication for vMCP.
44
---
55

6-
Virtual MCP implements a two-boundary authentication model that separates client
7-
authentication from backend authentication, giving you centralized control over
6+
Virtual MCP Server (vMCP) implements a two-boundary authentication model that
7+
separates client and backend authentication, giving you centralized control over
88
access while supporting diverse backend requirements.
99

1010
## Two-boundary authentication model
@@ -14,83 +14,86 @@ flowchart LR
1414
subgraph Boundary1[" "]
1515
direction TB
1616
Client[MCP Client]
17-
B1Label["**Boundary 1**<br>Client → Virtual MCP"]
17+
B1Label["**Boundary 1**<br>Client → vMCP"]
1818
end
1919
20-
subgraph vMCP[Virtual MCP Server]
21-
Auth[Token Validation]
22-
Backend[Backend Auth]
20+
subgraph vMCP["Virtual MCP Server (vMCP)"]
21+
Auth[Token validation]
22+
Backend[Backend auth]
2323
end
2424
2525
subgraph Boundary2[" "]
2626
direction TB
27-
B2Label["**Boundary 2**<br>Virtual MCP → Backend APIs"]
27+
B2Label["**Boundary 2**<br>vMCP → Backend APIs"]
2828
GitHub[GitHub API]
2929
Jira[Jira API]
3030
end
3131
32-
Client -->|"vMCP-scoped token"| Auth
32+
Client -->|"vMCP-scoped<br>token"| Auth
3333
Auth --> Backend
34-
Backend -->|"Backend-scoped token"| GitHub
35-
Backend -->|"Backend-scoped token"| Jira
34+
Backend -->|"Backend-scoped<br>token"| GitHub
35+
Backend -->|"Backend-scoped<br>token"| Jira
3636
```
3737

38-
**Boundary 1 (Incoming):** Clients authenticate to Virtual MCP using the
39-
mechanism defined in the MCP specification. This is your organization's identity
40-
layer.
38+
**Boundary 1 (Incoming):** Clients authenticate to vMCP using OAuth 2.1
39+
authorization as defined in the
40+
[MCP specification](https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization).
41+
This is your organization's identity layer.
4142

42-
**Boundary 2 (Outgoing):** Virtual MCP obtains appropriate credentials for each
43+
**Boundary 2 (Outgoing):** vMCP obtains appropriate credentials for each
4344
backend. Each backend API receives a token or credential scoped to its
4445
requirements.
4546

4647
## Incoming authentication
4748

48-
Configure how clients authenticate to Virtual MCP.
49+
Configure how clients authenticate to vMCP.
4950

5051
### Anonymous (development only)
5152

52-
No authentication required. Use only for local development.
53+
No authentication required:
5354

54-
```yaml
55+
```yaml title="VirtualMCPServer resource"
5556
spec:
5657
incomingAuth:
5758
type: anonymous
5859
```
5960
6061
:::warning
6162
62-
Never use `anonymous` incoming authentication in production environments.
63+
Do not use `anonymous` authentication in production environments. This setting
64+
disables all access control, allowing anyone to use the vMCP without
65+
credentials.
6366

6467
:::
6568

6669
### OIDC authentication
6770

6871
Validate tokens from an external identity provider:
6972

70-
```yaml
73+
```yaml title="VirtualMCPServer resource"
7174
spec:
7275
incomingAuth:
7376
type: oidc
7477
oidcConfig:
7578
type: inline
7679
inline:
7780
issuer: https://auth.example.com
78-
clientId: your-client-id
81+
clientId: <YOUR_CLIENT_ID>
7982
audience: vmcp
8083
```
8184

8285
When using an identity provider that issues opaque OAuth tokens, add a
8386
`clientSecretRef` referencing a Kubernetes Secret to enable token introspection:
8487

85-
```yaml
88+
```yaml title="VirtualMCPServer resource"
8689
spec:
8790
incomingAuth:
8891
type: oidc
8992
oidcConfig:
9093
type: inline
9194
inline:
9295
issuer: https://auth.example.com
93-
clientId: your-client-id
96+
clientId: <YOUR_CLIENT_ID>
9497
audience: vmcp
9598
clientSecretRef:
9699
name: oidc-client-secret
@@ -107,14 +110,14 @@ metadata:
107110
namespace: toolhive-system
108111
type: Opaque
109112
stringData:
110-
clientSecret: your-client-secret
113+
clientSecret: <YOUR_CLIENT_SECRET>
111114
```
112115

113116
### Kubernetes service account tokens
114117

115118
Authenticate using Kubernetes service account tokens for in-cluster clients:
116119

117-
```yaml
120+
```yaml title="VirtualMCPServer resource"
118121
spec:
119122
incomingAuth:
120123
type: oidc
@@ -132,15 +135,15 @@ validates service account tokens. The defaults work for most clusters:
132135

133136
## Outgoing authentication
134137

135-
Configure how Virtual MCP authenticates to backend MCP servers.
138+
Configure how vMCP authenticates to backend MCP servers.
136139

137140
### Discovery mode
138141

139-
When using discovery mode, Virtual MCP checks each backend MCPServer's
142+
When using discovery mode, vMCP checks each backend MCPServer's
140143
`externalAuthConfigRef` to determine how to authenticate. If a backend has no
141-
auth config, Virtual MCP connects without authentication.
144+
auth config, vMCP connects without authentication.
142145

143-
```yaml
146+
```yaml title="VirtualMCPServer resource"
144147
spec:
145148
outgoingAuth:
146149
source: discovered
@@ -150,6 +153,10 @@ This is the recommended approach for most deployments. Backends that don't
150153
require authentication work automatically, while backends with
151154
`externalAuthConfigRef` configured use their specified authentication method.
152155

156+
See
157+
[Configure token exchange for backend authentication](../guides-k8s/token-exchange-k8s.mdx)
158+
for details on using service account token exchange for backend authentication.
159+
153160
## Related information
154161

155162
- [Authentication framework concepts](../concepts/auth-framework.mdx)

0 commit comments

Comments
 (0)