Skip to content

Conversation

@yrobla
Copy link
Contributor

@yrobla yrobla commented Nov 26, 2025

Add runtime authentication discovery for VirtualMCPServer, enabling vMCP
to automatically discover and apply authentication configurations from
backend MCPServer ExternalAuthConfigRefs.

Changes:

  • Add DiscoverAndResolveAuth() function in converters package to fetch and convert MCPExternalAuthConfig to auth strategy metadata with dynamic secret resolution from Kubernetes
  • Implement discoverAuthConfig() in k8s workload discoverer to populate backend AuthStrategy and AuthMetadata fields from ExternalAuthConfigRef
  • Add applyAuthConfigToBackend() method in aggregator discoverer to decide which auth to use based on source mode (discovered/mixed/inline)
  • Add comprehensive unit tests for auth discovery scenarios (token exchange, header injection, no auth, error cases)
  • Add e2e test validating discovered auth with real MCP requests, tool aggregation, and tool calls through VirtualMCPServer

The discovered mode allows backends with heterogeneous authentication
(OAuth 2.0 token exchange, API key header injection, or no auth) to
coexist in the same group, with vMCP automatically discovering and
applying the appropriate auth to each backend request.

🤖 Generated with Claude Code

Large PR Justification

This PR implements the "discovered" mode for vMCP authentication, which requires atomic changes across multiple interconnected components:

Why this must be large:

  1. Atomic feature implementation: The discovered auth mode requires coordinated changes across three core subsystems that must work together:

    • Auth converters: Fetch and resolve auth configs from Kubernetes
    • Workload discoverer: Populate backend auth fields during discovery
    • Backend aggregator: Apply correct auth based on source mode (discovered/mixed/inline)

    Splitting these would create non-functional intermediate states.

  2. Comprehensive test coverage: Includes unit tests (9 test cases, ~490 lines) and e2e test (~620 lines) that validate the entire flow with real
    Kubernetes resources and MCP protocol requests. Tests cannot be added separately without the implementation.

  3. Multi-auth support: Handles heterogeneous authentication (OAuth 2.0, API keys, no auth) in a single group, requiring all converter logic
    present simultaneously.

Lines breakdown:

  • Implementation: ~150 lines across 3 files
  • Tests: ~1,110 lines (comprehensive validation)

The size delivers a complete, testable, production-ready feature atomically.

@github-actions github-actions bot added the size/XL Extra large PR: 1000+ lines changed label Nov 26, 2025
Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Large PR Detected

This PR exceeds 1000 lines of changes and requires justification before it can be reviewed.

How to unblock this PR:

Add a section to your PR description with the following format:

## Large PR Justification [Explain why this PR must be large, such as:] - Generated code that cannot be split - Large refactoring that must be atomic - Multiple related changes that would break if separated - Migration or data transformation

Alternative:

Consider splitting this PR into smaller, focused changes (< 1000 lines each) for easier review and reduced risk.

See our Contributing Guidelines for more details.


This review will be automatically dismissed once you add the justification section.

@codecov
Copy link

codecov bot commented Nov 26, 2025

Codecov Report

❌ Patch coverage is 68.75000% with 20 lines in your changes missing coverage. Please review.
✅ Project coverage is 56.18%. Comparing base (3e4fd23) to head (c977a17).
⚠️ Report is 12 commits behind head on main.

Files with missing lines Patch % Lines
pkg/vmcp/auth/converters/interface.go 0.00% 20 Missing ⚠️
Additional details and impacted files
@@ Coverage Diff @@ ## main #2747 +/- ## ========================================== + Coverage 55.96% 56.18% +0.21%  ========================================== Files 318 318 Lines 30677 30733 +56 ========================================== + Hits 17168 17266 +98  + Misses 12022 11973 -49  - Partials 1487 1494 +7 

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
@yrobla yrobla force-pushed the feat/discover_auth branch from d58778c to ba6c538 Compare November 26, 2025 15:55
@github-actions github-actions bot added size/XL Extra large PR: 1000+ lines changed and removed size/XL Extra large PR: 1000+ lines changed labels Nov 26, 2025
@github-actions github-actions bot dismissed their stale review November 26, 2025 15:55

Large PR justification has been provided. Thank you!

@github-actions
Copy link
Contributor

✅ Large PR justification has been provided. The size review has been dismissed and this PR can now proceed with normal review.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements discovered mode for VirtualMCPServer authentication, enabling vMCP to automatically discover and apply authentication configurations from backend MCPServer ExternalAuthConfigRefs at runtime. This allows backends with heterogeneous authentication strategies (OAuth 2.0 token exchange, API key header injection, or no auth) to coexist in the same MCPGroup.

Key Changes:

  • Added DiscoverAndResolveAuth() function in converters package to fetch MCPExternalAuthConfig from Kubernetes and resolve secrets dynamically
  • Implemented discoverAuthConfig() in k8s workload discoverer to populate backend AuthStrategy and AuthMetadata fields during discovery
  • Added applyAuthConfigToBackend() method in aggregator discoverer to handle auth source mode logic (discovered/mixed/inline)

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
pkg/vmcp/auth/converters/interface.go Adds DiscoverAndResolveAuth() function to fetch and convert MCPExternalAuthConfig to auth strategy metadata with secret resolution
pkg/vmcp/workloads/k8s.go Implements discoverAuthConfig() to populate backend auth fields from ExternalAuthConfigRef during workload discovery
pkg/vmcp/aggregator/discoverer.go Adds applyAuthConfigToBackend() to decide which auth to use based on source mode (discovered/mixed/inline)
pkg/vmcp/workloads/k8s_test.go Comprehensive unit tests covering token exchange, header injection, no auth, and error scenarios (9 test cases)
test/e2e/thv-operator/virtualmcp/virtualmcp_auth_discovery_test.go E2E test validating discovered auth with real MCP requests, tool aggregation, and heterogeneous auth backends

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

 Add runtime authentication discovery for VirtualMCPServer, enabling vMCP to automatically discover and apply authentication configurations from backend MCPServer ExternalAuthConfigRefs. Changes: - Add DiscoverAndResolveAuth() function in converters package to fetch and convert MCPExternalAuthConfig to auth strategy metadata with dynamic secret resolution from Kubernetes - Implement discoverAuthConfig() in k8s workload discoverer to populate backend AuthStrategy and AuthMetadata fields from ExternalAuthConfigRef - Add applyAuthConfigToBackend() method in aggregator discoverer to decide which auth to use based on source mode (discovered/mixed/inline) - Add comprehensive unit tests for auth discovery scenarios (token exchange, header injection, no auth, error cases) - Add e2e test validating discovered auth with real MCP requests, tool aggregation, and tool calls through VirtualMCPServer The discovered mode allows backends with heterogeneous authentication (OAuth 2.0 token exchange, API key header injection, or no auth) to coexist in the same group, with vMCP automatically discovering and applying the appropriate auth to each backend request. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
@yrobla yrobla force-pushed the feat/discover_auth branch from ba6c538 to c977a17 Compare November 26, 2025 16:19
@github-actions github-actions bot added size/XL Extra large PR: 1000+ lines changed and removed size/XL Extra large PR: 1000+ lines changed labels Nov 26, 2025
@tgrunnagle
Copy link
Contributor

@claude Please review this PR

@claude
Copy link
Contributor

claude bot commented Nov 26, 2025

Claude finished @tgrunnagle's task —— View job


PR Review: Discovered Mode for vMCP Authentication

Review Complete ✓


Overview

This PR implements runtime authentication discovery for VirtualMCPServer, enabling vMCP to automatically discover and apply authentication configurations from backend MCPServer ExternalAuthConfigRefs. The implementation is well-structured and follows ToolHive's architecture patterns.

Code Quality & Architecture

Strengths

  1. Clean separation of concerns: The implementation properly separates auth conversion (pkg/vmcp/auth/converters), workload discovery (pkg/vmcp/workloads), and aggregation logic (pkg/vmcp/aggregator).

  2. Excellent test coverage: The PR includes comprehensive unit tests (9 test cases covering all auth scenarios) and a thorough e2e test that validates the entire flow with real Kubernetes resources and MCP protocol requests.

  3. Error handling: Auth discovery errors are handled gracefully - backends can still be used without auth if discovery fails, with appropriate warnings logged.

  4. Registry pattern: The converter registry pattern in pkg/vmcp/auth/converters/interface.go is well-designed and extensible for future auth types.

  5. Documentation: Function comments clearly explain behavior, particularly the return value semantics (e.g., when nil error is expected vs. actual errors).

Issues & Recommendations

1. Error Message Missing Namespace Context ⚠️

Location: pkg/vmcp/auth/converters/interface.go:170

return "", nil, fmt.Errorf("failed to get MCPExternalAuthConfig %s: %w", externalAuthConfigRef.Name, err)

Issue: The error message doesn't include the namespace, which would be helpful for debugging in multi-namespace environments.

Recommendation: Include namespace in the error message:

return "", nil, fmt.Errorf("failed to get MCPExternalAuthConfig %s in namespace %s: %w", externalAuthConfigRef.Name, namespace, err)

This was also identified by the Copilot reviewer and should be addressed.

2. Coverage Gap Investigation ℹ️

Location: pkg/vmcp/auth/converters/interface.go:150-195

Codecov reports 20 lines missing coverage in the DiscoverAndResolveAuth function. However, examining the test code shows:

  • k8s_test.go tests GetWorkloadAsVMCPBackend (lines 35-320)
  • This calls discoverAuthConfig at k8s.go:184
  • Which calls converters.DiscoverAndResolveAuth at k8s.go:201

The code IS being tested through the call chain. The coverage gap is likely a test instrumentation issue where coverage isn't being properly attributed to the converters package. This is not a blocking issue but worth investigating.

3. Auth Mode Logic Clarity ℹ️

Location: pkg/vmcp/aggregator/discoverer.go:178-182

The "discovered" mode logic is correct, but consider: if Source = "discovered" with no Default config AND the backend has no discovered auth, the backend will have no auth at all. This might be intentional, but consider logging a warning when this happens to help operators debug missing auth.

Test Quality Assessment

Unit Tests - pkg/vmcp/workloads/k8s_test.go

Excellent coverage of auth discovery scenarios:

  • ✅ Token exchange auth with secret resolution (lines 35-114)
  • ✅ Header injection auth with secret resolution (lines 116-189)
  • ✅ No auth config (lines 191-225)
  • ✅ Auth config not found error handling (lines 227-263)
  • ✅ Secret not found error handling (lines 265-320)
  • ✅ Basic backend field mapping (lines 322-359)
  • ✅ Transport type handling (lines 361-393)
  • ✅ Annotation filtering (lines 395-432)
  • ✅ Group workload listing (lines 434-487)

Unit Tests - pkg/vmcp/aggregator/discoverer_test.go

Comprehensive coverage of auth mode logic (lines 412-898):

  • ✅ Discovered mode with discovered auth preserved
  • ✅ Discovered mode without discovered auth falls back to config
  • ✅ Mixed mode with explicit config override
  • ✅ Mixed mode without explicit config uses discovered auth
  • ✅ Inline mode ignores discovered auth
  • ✅ Empty source mode behaves like inline
  • ✅ Unknown source mode defaults to config-based auth
  • ✅ Nil auth config does nothing
  • ✅ Multiple auth types (token exchange, header injection)
  • ✅ Fallback to default config

This is exemplary test coverage.

E2E Test - virtualmcp_auth_discovery_test.go

Outstanding end-to-end validation:

  • ✅ Creates real Kubernetes resources (secrets, auth configs, backends, vMCP server)
  • ✅ Tests heterogeneous auth (OAuth 2.0 token exchange, API key header injection, no auth)
  • ✅ Validates tool aggregation across backends with different auth
  • ✅ Makes actual MCP protocol requests (initialize, list tools, call tool)
  • ✅ Uses mock HTTP server to avoid external dependencies
  • ✅ Proper cleanup in AfterAll
  • ✅ Good use of Ginkgo's Eventually for async operations

Minor suggestion: Consider adding a negative test case where auth discovery fails (e.g., missing secret) to verify the fallback behavior works in a real cluster.

Security Considerations ✅

  1. Secret handling: Secrets are properly resolved from Kubernetes and not logged (good practice).
  2. Error messages: Error messages don't leak sensitive information.
  3. Auth fallback: When auth discovery fails, the backend is still created but without auth (logged as warning). This is appropriate for resilience.

Performance Considerations ℹ️

  1. Secret fetching: Each backend with auth requires fetching secrets from Kubernetes synchronously during discovery. For large numbers of backends, consider caching or parallel fetching in future iterations.
  2. Registry singleton: The DefaultRegistry() uses sync.Once for lazy initialization - good pattern.

Documentation ✅

The code is well-documented with:

  • Clear function comments explaining parameters and return values
  • Inline comments explaining design decisions
  • Good examples in test cases

Consider adding:

  • Architecture documentation in docs/arch/ explaining the discovered auth mode (per CLAUDE.md guidelines)
  • Examples in user-facing documentation showing how to configure discovered auth

Verdict

This is a high-quality PR with:

  • ✅ Clean architecture and code organization
  • ✅ Comprehensive test coverage (unit + e2e)
  • ✅ Proper error handling
  • ✅ Good documentation
  • ⚠️ One minor issue: error message missing namespace context (easy fix)
  • ℹ️ Coverage gap in interface.go (likely test instrumentation issue, not actual missing tests)

Recommended Actions

Required:

  1. Fix error message to include namespace context (interface.go:170)

Optional:

  1. Investigate Codecov coverage gap (likely false negative)
  2. Consider adding negative test case to e2e test for failed auth discovery
  3. Add architecture documentation for discovered auth mode (per CLAUDE.md guidelines)
  4. Consider logging warning when discovered mode has no auth and no default fallback

Summary

The PR correctly implements the complex auth discovery logic with excellent test coverage. The implementation handles heterogeneous authentication across backends elegantly. After fixing the error message issue, this is ready to merge.


@yrobla yrobla merged commit 66fff4a into main Nov 27, 2025
59 of 60 checks passed
@yrobla yrobla deleted the feat/discover_auth branch November 27, 2025 10:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/XL Extra large PR: 1000+ lines changed

6 participants