Skip to content

Add MCPServerEntry validation controller and MCPGroup integration#4664

Merged
JAORMX merged 7 commits intomainfrom
jaormx/mcpserverentry-controller
Apr 9, 2026
Merged

Add MCPServerEntry validation controller and MCPGroup integration#4664
JAORMX merged 7 commits intomainfrom
jaormx/mcpserverentry-controller

Conversation

@JAORMX
Copy link
Copy Markdown
Collaborator

@JAORMX JAORMX commented Apr 8, 2026

Summary

MCPServerEntry needs a controller to validate that referenced resources exist and to integrate with MCPGroup for discovery. This is the second PR in the RFC-55 implementation series, building on #4662 (CRD types).

  • Introduce a validation-only controller that checks MCPGroup, MCPExternalAuthConfig, and CA bundle ConfigMap references exist, setting GroupRefValidated, ExternalAuthConfigValidated, and CABundleRefValidated conditions
  • The controller never creates infrastructure (no pods, services, deployments) and never probes remote URLs
  • Integrate MCPServerEntry into the MCPGroup controller: track membership in Entries/EntryCount, handle deletion notifications, watch for entry changes
  • Wire field indexing for MCPServerEntry.Spec.GroupRef and register the controller in the operator main setup
  • Watch MCPExternalAuthConfig, MCPGroup, and ConfigMap changes to re-validate entries when referenced resources are created/updated/deleted
  • Use Failed phase (not Pending) when validations fail, matching the semantic distinction documented in the types

Refs #4656

Type of change

  • New feature

Large PR Justification

  • The diff is inflated by ~710 lines because Add custom CA certificate support for OTLP endpoints #4676 accidentally deleted mcpserverentry_types.go and both CRD YAML files that Add MCPServerEntry CRD types and MCPGroup status fields #4662 had already merged — those appear as new additions here but are restorations, not new code
  • Excluding tests (538 lines), generated RBAC/CRD manifests (544 lines), and docs (104 lines), the actual new production code is ~427 lines (the controller) + ~127 lines (MCPGroup integration) + ~38 lines (main.go wiring)
  • The controller + MCPGroup integration is a single logical change that cannot be split without shipping a controller with no tests or an MCPGroup integration with no controller

Test plan

  • Unit tests (task test) — operator unit tests pass, including 8 table-driven subtests for MCPServerEntryReconciler and MCPGroup entry integration/deletion tests
  • Linting (task lint-fix) — 0 issues
  • RBAC regenerated via task operator-manifests

Changes

File Change
mcpserverentry_types.go Remove unused AllowInsecureAnnotation, align condition type names with shared constants
mcpserverentry_controller.go New validation-only controller: validates GroupRef (existence + Ready phase), AuthConfig, CABundle; watches MCPGroup, ConfigMap, and AuthConfig; field-indexed lookups; transient errors requeue instead of persisting misleading conditions
mcpgroup_controller.go Add MCPServerEntry integration: finder, populator, deletion handler, watch
main.go Extract setupGroupRefFieldIndexes, add MCPServerEntry controller setup
mcpserverentry_controller_test.go 8 table-driven subtests + MCPGroup entry integration and deletion handler tests
mcpgroup_controller_test.go Add MCPServerEntry field index to all fake client builders
test-integration/*/suite_test.go Fix field indexer nesting bug (was inside MCPRemoteProxy error block) in 5 suites
role.yaml, CRD YAMLs, crd-api.md Generated RBAC and CRD updates
chainsaw/*/assert-rbac-clusterrole.yaml Add MCPServerEntry to RBAC assertions

Special notes for reviewers

  • The controller has no finalizer since it owns no external resources. MCPGroup handles the "member disappeared" case via its existing watch pattern.
  • Transient errors (non-NotFound) from Get calls are returned to controller-runtime for requeue rather than persisting a potentially misleading condition. Detailed errors are logged server-side only.
  • SSRF-style URL validation for RemoteURL is tracked separately in Add URL validation to reject internal/metadata endpoints in RemoteURL fields #4695 — the existing ^https?:// CEL pattern matches what MCPRemoteProxy already uses today.

Generated with Claude Code

@github-actions github-actions bot added the size/M Medium PR: 300-599 lines changed label Apr 8, 2026
@codecov
Copy link
Copy Markdown

codecov bot commented Apr 8, 2026

Codecov Report

❌ Patch coverage is 47.60563% with 186 lines in your changes missing coverage. Please review.
✅ Project coverage is 68.60%. Comparing base (3c5da31) to head (01991e7).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
...-operator/controllers/mcpserverentry_controller.go 52.15% 118 Missing and 4 partials ⚠️
...md/thv-operator/controllers/mcpgroup_controller.go 43.58% 39 Missing and 5 partials ⚠️
cmd/thv-operator/main.go 0.00% 20 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4664      +/-   ##
==========================================
- Coverage   68.66%   68.60%   -0.07%     
==========================================
  Files         509      515       +6     
  Lines       52987    53518     +531     
==========================================
+ Hits        36384    36715     +331     
- Misses      13782    13961     +179     
- Partials     2821     2842      +21     

☔ 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.

@github-actions github-actions bot added size/L Large PR: 600-999 lines changed and removed size/M Medium PR: 300-599 lines changed labels Apr 8, 2026
Copy link
Copy Markdown
Contributor

@jhrozek jhrozek left a comment

Choose a reason for hiding this comment

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

Review of the controller and MCPGroup integration. Types-level comments on #4662.

@JAORMX JAORMX force-pushed the jaormx/mcpserverentry-types branch from 94d87f1 to a57d60d Compare April 8, 2026 11:42
Base automatically changed from jaormx/mcpserverentry-types to main April 8, 2026 14:48
Copy link
Copy Markdown
Collaborator

@ChrisJBurns ChrisJBurns left a comment

Choose a reason for hiding this comment

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

Agent-Assisted Code Review

This review was performed by three specialized agents: kubernetes-expert, code-reviewer, and security-advisor. Each finding is attributed to the agent(s) that identified it.

Summary

Priority Count Description
Must fix 3 Integration test nesting bug, AllowInsecureAnnotation dead code, overly broad RBAC
Should fix/defer 4 Failed phase never used, unused constant, condition naming inconsistency, missing ConfigMap watch
Medium 4 SSRF protection, client-side filtering, all-or-nothing status clearing, error info leak
Minor 1 Test field indexer duplication

Positive Aspects

  • Clean validate-then-update-status pattern with no infrastructure side effects
  • Good use of RequeueAfter: 500ms for conflict handling (consistent with existing controllers)
  • Correct finalizer decision (none needed for validation-only controller)
  • setupGroupRefFieldIndexes extraction is a nice improvement to main.go
  • MCPGroup integration faithfully follows established patterns for MCPServer and MCPRemoteProxy
  • CRD YAML, Helm charts, RBAC, and API docs are consistent and complete
  • Short name mse is well-chosen

Generated with Claude Code

@JAORMX JAORMX force-pushed the jaormx/mcpserverentry-controller branch from 6fcd0e8 to 3062bb6 Compare April 8, 2026 17:23
@github-actions github-actions bot added size/XL Extra large PR: 1000+ lines changed and removed size/L Large PR: 600-999 lines changed labels Apr 8, 2026
Copy link
Copy Markdown
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.

ChrisJBurns
ChrisJBurns previously approved these changes Apr 8, 2026
jhrozek
jhrozek previously approved these changes Apr 8, 2026
Copy link
Copy Markdown
Contributor

@jhrozek jhrozek left a comment

Choose a reason for hiding this comment

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

looks good but there are conflicts

JAORMX and others added 3 commits April 9, 2026 06:58
Introduce a validation-only controller for MCPServerEntry that checks
referenced resources (MCPGroup, MCPExternalAuthConfig, CA bundle
ConfigMap) exist and sets status conditions accordingly. The controller
never creates infrastructure or probes remote URLs.

Integrate MCPServerEntry into the MCPGroup controller so groups track
entry membership in Entries/EntryCount status fields, handle entry
deletion notifications, and watch for entry changes.

Wire up field indexing for MCPServerEntry.Spec.GroupRef and register
the controller in the operator's server controller setup. Extract
field indexer setup into setupGroupRefFieldIndexes to keep
setupServerControllers under the cyclomatic complexity limit.

Refs: #4656

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…uites

The Chainsaw E2E tests assert on the exact ClusterRole contents, and
the integration test suites need field indexers for all types that
reference MCPGroup via spec.groupRef.

Add mcpserverentries and mcpserverentries/status to the RBAC golden
files for both multi-tenancy and single-tenancy Chainsaw test setups.
Register MCPServerEntry field indexer in all five integration test
suite BeforeSuite blocks.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix RBAC: reduce mcpserverentries verbs to get;list;watch (validation-only)
- Fix field indexer nesting bug in 4 integration test suites where
  MCPServerEntry indexer was unreachable on the happy path
- Add MCPGroup Ready phase check in validateGroupRef, matching
  MCPServer/MCPRemoteProxy behavior
- Return transient errors for requeue instead of persisting misleading
  NotFound conditions; sanitize error messages in status conditions
- Add watches for MCPGroup and ConfigMap changes to re-validate entries
- Use field indexes for auth config and CA bundle ConfigMap lookups
- Use Failed phase when validations fail (Pending is initial-only)
- Remove unused AllowInsecureAnnotation constant and misleading doc
- Align condition type names with shared constants from mcpserver_types
- Add unit tests for MCPServerEntry controller and MCPGroup entry methods
- Regenerate RBAC manifests and CRD API docs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@JAORMX JAORMX dismissed stale reviews from jhrozek and ChrisJBurns via c66df7c April 9, 2026 06:59
@JAORMX JAORMX force-pushed the jaormx/mcpserverentry-controller branch from 3062bb6 to c66df7c Compare April 9, 2026 06:59
@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 Apr 9, 2026
rdimitrov
rdimitrov previously approved these changes Apr 9, 2026
jhrozek
jhrozek previously approved these changes Apr 9, 2026
@github-actions github-actions bot removed the size/XL Extra large PR: 1000+ lines changed label Apr 9, 2026
@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 Apr 9, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 9, 2026

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

@github-actions github-actions bot dismissed their stale review April 9, 2026 07:07

Large PR justification has been provided. Thank you!

@github-actions github-actions bot added the size/XL Extra large PR: 1000+ lines changed label Apr 9, 2026
Signed-off-by: Juan Antonio Osorio <ozz@stacklok.com>
@JAORMX JAORMX dismissed stale reviews from jhrozek and rdimitrov via def7bed April 9, 2026 07:31
@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 Apr 9, 2026
The MCPGroup controller references Entries and EntryCount on
MCPGroupStatus for tracking MCPServerEntry membership, but the
fields were not defined on the type. This caused compilation
failures across lint, tests, vuln check, helm, and E2E CI jobs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@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 Apr 9, 2026
The chainsaw E2E setup test expected mcpserverentries in the full CRUD
resource list, but the generated role correctly places it in a separate
read-only rule alongside virtualmcpcompositetooldefinitions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@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 Apr 9, 2026
The MCPServerEntry controller needs only read access (get/list/watch)
to mcpserverentries, not full CRUD. The generated role.yaml correctly
groups mcpserverentries with virtualmcpcompositetooldefinitions in a
read-only rule, but the chainsaw assertion files were out of sync:
multi-tenancy was missing mcpserverentries entirely, and single-tenancy
had it in the full-CRUD block.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@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 Apr 9, 2026
@JAORMX JAORMX merged commit b542727 into main Apr 9, 2026
40 checks passed
@JAORMX JAORMX deleted the jaormx/mcpserverentry-controller branch April 9, 2026 09:18
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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants