Skip to content

Commit 9312f00

Browse files
committed
Add Virtual MCP Server proposal
This proposal introduces a Virtual MCP Server that aggregates multiple MCP servers from a ToolHive group into a single unified interface. Key features: - Leverages existing ToolHive groups for backend management - Uses existing ToolsFilter and ToolOverride constructs - Supports per-backend authentication strategies - Enables composite tools for cross-service workflows - Maintains full MCP protocol compatibility The Virtual MCP Server will simplify client integration by providing a single connection point while handling the complexity of multiple backend authentication requirements and tool namespace management. Signed-off-by: Juan Antonio Osorio <[email protected]>
1 parent bc1d063 commit 9312f00

File tree

1 file changed

+252
-0
lines changed

1 file changed

+252
-0
lines changed
Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
# Virtual MCP Server
2+
3+
## Problem Statement
4+
5+
Organizations need to consolidate multiple MCP servers into a unified interface for complex workflows spanning multiple tools and services. Currently, clients must manage connections to individual MCP servers separately, leading to complexity in orchestration and authentication management.
6+
7+
## Goals
8+
9+
- Aggregate multiple MCP servers from a ToolHive group into a single virtual MCP server
10+
- Enable tool namespace management and conflict resolution
11+
- Support composite tools for multi-step workflows across backends
12+
- Handle per-backend authentication/authorization requirements
13+
- Maintain full MCP protocol compatibility
14+
15+
## Proposed Solution
16+
17+
### High-Level Design
18+
19+
The Virtual MCP Server (`thv virtual`) acts as an aggregation proxy that:
20+
1. References an existing ToolHive group containing multiple MCP server workloads
21+
2. Discovers and merges capabilities (tools, resources, prompts) from all workloads
22+
3. Routes incoming MCP requests to appropriate backend workloads
23+
4. Manages per-backend authentication requirements
24+
25+
```
26+
MCP Client → Virtual MCP → [Workload A, Workload B, ... from Group]
27+
```
28+
29+
### Configuration Schema
30+
31+
```yaml
32+
# virtual-mcp-config.yaml
33+
version: v1
34+
name: "engineering-tools"
35+
description: "Virtual MCP for engineering team"
36+
37+
# Reference existing ToolHive group (required)
38+
group: "engineering-team"
39+
40+
# Tool aggregation using existing ToolHive constructs
41+
aggregation:
42+
conflict_resolution: "prefix" # prefix | priority | manual
43+
44+
tools:
45+
- workload: "github"
46+
# Filter to only include specific tools (uses existing ToolsFilter)
47+
filter: ["create_pr", "merge_pr", "list_issues"]
48+
# Override tool names/descriptions (uses existing ToolOverride)
49+
overrides:
50+
create_pr:
51+
name: "gh_create_pr"
52+
description: "Create a GitHub pull request"
53+
54+
- workload: "jira"
55+
# If no filter specified, all tools are included
56+
overrides:
57+
create_issue:
58+
name: "jira_create_issue"
59+
60+
- workload: "slack"
61+
# No filter or overrides - include all tools as-is
62+
63+
# Per-backend authentication
64+
backend_auth:
65+
github:
66+
type: "token_exchange"
67+
token_url: "https://github.com/oauth/token"
68+
audience: "github-api"
69+
client_id_ref:
70+
name: "github-oauth"
71+
key: "client_id"
72+
73+
jira:
74+
type: "pass_through"
75+
76+
internal_db:
77+
type: "service_account"
78+
credentials_ref:
79+
name: "db-creds"
80+
key: "token"
81+
82+
slack:
83+
type: "header_injection"
84+
headers:
85+
- name: "Authorization"
86+
value_ref:
87+
name: "slack-creds"
88+
key: "bot_token"
89+
90+
# Composite tools (Phase 2)
91+
composite_tools:
92+
- name: "deploy_and_notify"
93+
description: "Deploy PR and notify team"
94+
parameters:
95+
pr_number: {type: "integer"}
96+
steps:
97+
- id: "merge"
98+
tool: "github.merge_pr"
99+
arguments: {pr: "{{.params.pr_number}}"}
100+
101+
- id: "notify"
102+
tool: "slack.send"
103+
arguments: {text: "Deployed PR {{.params.pr_number}}"}
104+
depends_on: ["merge"]
105+
106+
# Operational settings
107+
operational:
108+
timeouts:
109+
default: 30s
110+
per_workload:
111+
github: 45s
112+
113+
failover:
114+
strategy: "automatic"
115+
```
116+
117+
### Key Features
118+
119+
#### 1. Group-Based Backend Management
120+
121+
Virtual MCP references a ToolHive group and automatically discovers all workloads within it:
122+
- Leverages existing `groups.Manager` and `workloads.Manager`
123+
- Dynamic workload discovery via `ListWorkloadsInGroup()`
124+
- Inherits workload configurations from group
125+
126+
#### 2. Capability Aggregation
127+
128+
Merges MCP capabilities from all backends:
129+
- **Tools**: Aggregated with namespace conflict resolution
130+
- **Resources**: Combined from all backends
131+
- **Prompts**: Merged with prefixing
132+
- **Logging/Sampling**: Enabled if any backend supports it
133+
134+
#### 3. Tool Filtering and Overrides
135+
136+
Uses existing ToolHive constructs:
137+
- **ToolsFilter**: Include only specific tools from a workload
138+
- **ToolOverride**: Rename tools and update descriptions to avoid conflicts
139+
140+
#### 4. Per-Backend Authentication
141+
142+
Different backends may require different authentication strategies:
143+
- **pass_through**: Forward client credentials unchanged
144+
- **token_exchange**: Exchange incoming token for backend-specific token (RFC 8693)
145+
- **service_account**: Use stored credentials for backend
146+
- **header_injection**: Add authentication headers from secrets
147+
- **mapped_claims**: Transform JWT claims for backend requirements
148+
149+
Example authentication flow:
150+
```
151+
Client → (Bearer token for Virtual MCP) → Virtual MCP
152+
├→ GitHub backend (token exchanged for GitHub PAT)
153+
├→ Jira backend (original token passed through)
154+
└→ Internal DB (service account token injected)
155+
```
156+
157+
#### 5. Request Routing
158+
159+
Routes MCP protocol requests to appropriate backends:
160+
- Tool calls routed based on tool-to-workload mapping
161+
- Resource requests routed by resource namespace
162+
- Prompt requests handled similarly
163+
- Load balancing for duplicate capabilities
164+
165+
### CLI Usage
166+
167+
```bash
168+
# Start virtual MCP for a group
169+
thv virtual --group engineering-team --config virtual-config.yaml
170+
171+
# Quick start with defaults
172+
thv virtual --group engineering-team
173+
174+
# With inline tool filtering
175+
thv virtual --group engineering-team \
176+
--tools github:create_pr,merge_pr \
177+
--tools jira:create_issue
178+
179+
# With tool overrides file
180+
thv virtual --group engineering-team \
181+
--tools-override overrides.yaml
182+
```
183+
184+
### Implementation Phases
185+
186+
**Phase 1 (MVP)**: Basic aggregation
187+
- Group-based workload discovery
188+
- Tool aggregation with filter and override support
189+
- Simple request routing
190+
- Pass-through authentication
191+
192+
**Phase 2**: Advanced features
193+
- Composite tool execution
194+
- Per-backend authentication strategies
195+
- Token exchange support
196+
- Failover and load balancing
197+
198+
**Phase 3**: Enterprise features
199+
- Dynamic configuration updates
200+
- Multi-group support
201+
- Advanced routing strategies
202+
- Comprehensive observability
203+
204+
## Benefits
205+
206+
- **Simplified Client Integration**: Single MCP connection instead of multiple
207+
- **Unified Authentication**: Handle diverse backend auth requirements centrally
208+
- **Workflow Orchestration**: Composite tools enable cross-service workflows
209+
- **Operational Efficiency**: Centralized monitoring and management
210+
- **Backward Compatible**: Works with existing MCP clients and servers
211+
212+
## Implementation Notes
213+
214+
### Reusing Existing Components
215+
216+
The implementation will maximize reuse of existing ToolHive components:
217+
218+
1. **Tool Filtering**: Use existing `mcp.WithToolsFilter()` middleware
219+
2. **Tool Overrides**: Use existing `mcp.WithToolsOverride()` middleware
220+
3. **Groups**: Use `groups.Manager` for group operations
221+
4. **Workloads**: Use `workloads.Manager` for workload discovery
222+
5. **Authentication**: Extend existing auth middleware patterns
223+
224+
### Authentication Complexity
225+
226+
Different MCP servers may have vastly different authentication requirements:
227+
- Public servers may need no auth
228+
- Enterprise servers may require OAuth/OIDC
229+
- Internal services may use service accounts
230+
- Third-party APIs may need API keys
231+
232+
The Virtual MCP must handle this complexity transparently, maintaining separate authentication contexts per backend while presenting a unified interface to clients.
233+
234+
## Alternative Approaches Considered
235+
236+
1. **Kubernetes CRD**: More complex, requires operator changes
237+
2. **Standalone Service**: Loses integration with ToolHive infrastructure
238+
3. **LLM-generated backend**: Adds more randomness to the equation which is undesirable for agents.
239+
240+
## Open Questions
241+
242+
1. How to handle streaming responses across multiple backends?
243+
2. Should we cache backend capabilities or query dynamically?
244+
3. How to handle backend-specific rate limits?
245+
246+
## Success Criteria
247+
248+
- Aggregate 5+ MCP servers from a group with < 10ms routing overhead
249+
- Support 100+ concurrent client connections
250+
- Zero changes required to existing MCP servers or clients
251+
- Successfully handle different authentication methods per backend
252+
- Maintain existing tool filter and override semantics

0 commit comments

Comments
 (0)