-
Notifications
You must be signed in to change notification settings - Fork 135
Implement tool conflict resolution for Virtual MCP Server #2365
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
@claude please review this in context of docs/proposals/THV-2106-virtual-mcp-server.md . look for code quality, security and best practices. |
|
Claude finished @JAORMX's task —— View job Code Review CompleteI've reviewed this PR against the THV-2106 proposal and ToolHive best practices. Overall, this is excellent work with well-structured code, comprehensive tests, and smart reuse of existing middleware logic. Here's my detailed feedback: ✅ Strengths1. Excellent Code Reuse PatternThe extraction of
2. Well-Designed Conflict Resolution StrategiesAll three strategies are implemented correctly per the proposal:
3. Comprehensive Test Coverage
4. Good Logging and Observability
🔒 Security Review✅ No Security Issues Found
Minor Recommendation: DoS PreventionThe parallel backend queries use g.SetLimit(10) // pkg/vmcp/aggregator/default_aggregator.go:96Suggestion: Add 📋 Code Quality Issues1. Inconsistent Error Wrapping (Low Priority)Location: return nil, fmt.Errorf("%w: %s: %v", ErrBackendQueryFailed, backend.ID, err)Issue: Mixing sentinel error with formatted context makes errors harder to match with Recommendation: Choose one pattern consistently: // Option A: Pure sentinel error
return nil, fmt.Errorf("backend %s: %w", backend.ID, ErrBackendQueryFailed)
// Option B: Wrap with context (current approach is fine)
return nil, fmt.Errorf("%w: %s: %v", ErrBackendQueryFailed, backend.ID, err)2. Potential Memory Allocation Optimization (Very Low Priority)Location: simpleTools := make([]mcp.SimpleTool, len(tools))
originalToolsByName := make(map[string]vmcp.Tool, len(tools))Observation: Suggestion: Only allocate the map after filtering if many tools are typically filtered out. Current approach is fine for small tool lists. 3. Missing Edge Case Test (Medium Priority)Location: Test coverage for Missing: Test case where override references a tool that doesn't exist in the backend's tool list. Current code would fail silently. Recommendation: Add test case: {
name: "override references non-existent tool",
backendID: "github",
tools: []vmcp.Tool{
{Name: "real_tool", Description: "Real"},
},
workloadConfig: &config.WorkloadToolConfig{
Workload: "github",
Overrides: map[string]*config.ToolOverride{
"fake_tool": {Name: "renamed_fake"},
},
},
wantCount: 1,
wantNames: []string{"real_tool"},
},🎯 Alignment with Best Practices✅ Follows ToolHive Patterns
✅ Go Best Practices
|
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #2365 +/- ##
==========================================
+ Coverage 53.79% 54.22% +0.42%
==========================================
Files 254 259 +5
Lines 24509 24824 +315
==========================================
+ Hits 13185 13461 +276
- Misses 10039 10068 +29
- Partials 1285 1295 +10 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added some comments
|
@claude be cool and address the comments |
|
Claude finished @JAORMX's task —— View job Addressing Review Comments ✅All review comments from @yrobla have been addressed!
Changes Made
Test ResultsAll tests passing: CommitPushed commit |
f58142b to
530f2ab
Compare
Add three conflict resolution strategies (prefix, priority, manual) to handle
duplicate tool names across multiple backend MCP servers in vMCP aggregation.
This implements the aggregation conflict resolution portion of the Virtual MCP
Server proposal (THV-2106), enabling vMCP to merge capabilities from multiple
backends while resolving naming conflicts.
Key features:
- Prefix strategy: automatically prefixes tools with workload identifier
(supports {workload}_, {workload}., custom formats)
- Priority strategy: explicit ordering with first-wins semantics
(drops lower-priority conflicting tools with warnings)
- Manual strategy: requires explicit overrides with startup validation
(fails if any conflicts lack overrides, safest for production)
- Reuses existing mcp.WithToolsFilter/Override middleware logic
- Per-backend tool filtering and overrides applied before conflict resolution
- Tracks conflict metadata (count resolved, strategy used)
Implementation:
- Extracted shared filtering/override logic from pkg/mcp/tool_filter.go
- Created applyFilteringAndOverrides() as single source of truth
- Both HTTP middleware and aggregator use the same battle-tested code
- Updated defaultAggregator to integrate conflict resolver
- Comprehensive table-driven unit tests for all strategies
This follows DDD principles with clear bounded contexts and maintains
backward compatibility with existing middleware behavior.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add nil check in tool_adapter.go to prevent panic when tool not found in originalToolsByName map - Add comment explaining O(n²) complexity is acceptable for small tool lists - Improve warning message when priority strategy drops tools from backends not in priority list - Show which backends were involved when dropping conflicting tools Co-authored-by: Juan Antonio Osorio <JAORMX@users.noreply.github.com>
Address review feedback by adding detailed comments explaining: 1. What "resolved conflict" means in the context of conflict resolution: - Prefix strategy: Renaming tools proactively prevents collisions - Manual strategy: Explicit overrides resolve existing conflicts - Priority strategy: Drops duplicates rather than renaming 2. Manual resolver validation: Documents that collision detection after override prevents new conflicts from being introduced by bad config These clarifications help reviewers understand that renaming IS conflict resolution, not just a side effect. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Remove the ConflictsResolved counter as it was not defined in the proposal and caused confusion about what constitutes a "resolved conflict" vs a preventive renaming. The ConflictStrategy field remains to indicate which resolution approach was used (prefix, priority, manual), which is sufficient for observability. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Split conflict_resolver.go into focused files for better code organization: - prefix_resolver.go: PrefixConflictResolver implementation - priority_resolver.go: PriorityConflictResolver implementation - manual_resolver.go: ManualConflictResolver implementation - conflict_resolver.go: Factory function and shared helpers Each strategy now has its own file, making the code easier to navigate and maintain. Shared helpers (groupToolsByName, toolWithBackend) remain in conflict_resolver.go for reuse. No functional changes - pure refactoring. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2c5dc8c to
5a166ca
Compare
Change priority resolver to use prefix strategy for backends not in the priority list instead of dropping their conflicting tools. This prevents data loss while maintaining explicit control for prioritized backends. Behavior: - Backends in priority list: priority strategy (first wins) - Backends NOT in priority list with conflicts: prefix strategy fallback - Example: priority_order=["github"], but slack+teams both have "send_message" Result: "slack_send_message" and "teams_send_message" (both included) This addresses review feedback about dropping tools unnecessarily and provides a more practical default behavior. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
4beb517 to
1bd6867
Compare
Summary
Implements tool conflict resolution strategies for the Virtual MCP Server aggregation system. This enables vMCP to merge capabilities from multiple backend MCP servers while resolving duplicate tool names.
Three conflict resolution strategies:
Prefix Strategy: Automatically prefixes all tools with workload identifier (e.g.,
{workload}_,{workload}., custom formats). Deterministic and requires no configuration beyond format.Priority Strategy: Uses explicit priority ordering where first backend wins conflicts. Lower-priority conflicting tools are dropped with warnings. Non-conflicting tools from all backends are included.
Manual Strategy: Requires explicit overrides for ALL conflicts. Fails at startup with detailed error messages if any conflicts lack overrides. Safest option for production deployments.
Code reuse from existing middleware:
Extracted shared filtering/override logic from
pkg/mcp/tool_filter.gointoapplyFilteringAndOverrides()function. Both the HTTP middleware (battle-tested) and the new aggregator use this exact same code, ensuring consistency and reducing duplication.Key changes:
pkg/vmcp/aggregator/conflict_resolver.go- Three strategy implementationspkg/vmcp/aggregator/tool_adapter.go- Minimal adapter to reuse middleware logicpkg/vmcp/aggregator/default_aggregator.go- Integrated conflict resolverpkg/mcp/tool_filter.go- Extracted shared logic, addedApplyToolFiltering()APIPer-backend tool filtering and overrides:
Applied during capability discovery BEFORE conflict resolution using the existing
mcp.WithToolsFilter()andmcp.WithToolsOverride()patterns. This reduces the tool set entering conflict resolution.Test Plan
go test ./pkg/vmcp/aggregator ./pkg/mcp)task lint-fix){workload}_,{workload}.)Related
Part of Virtual MCP Server implementation (THV-2106). Builds on capability discovery work from PR #2354.
🤖 Generated with Claude Code