Skip to content

multi_valued_claims in MCPAuthzConfig is silently ignored for VirtualMCPServer #6737

Description

@ngocketit

Bug description

When a VirtualMCPServer references an MCPAuthzConfig that sets multi_valued_claims, the setting is accepted and validated but never reaches the Cedar authorizer. As a result, the claimset_<name> attribute documented in the authz policy reference (Multi-valued claim normalization) is never created, and Cedar policies that use it always deny.

No validation error or warning is emitted, so the misconfiguration is invisible.

Reproduction

Given an MCPAuthzConfig:

apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPAuthzConfig
metadata:
  name: example-authz
spec:
  type: cedarv1
  config:
    multi_valued_claims: ["scope"]
    entities_json: "[]"
    policies:
      - |
        permit(
          principal,
          action == Action::"call_tool",
          resource == Tool::"example_get-weather"
        ) when {
          principal has claimset_scope &&
          principal.claimset_scope.contains("weather:read")
        };

referenced by a VirtualMCPServer via spec.incomingAuth.authzConfigRef, and a token whose claims (JWT or RFC 7662 introspection) include:

{
  "active": true,
  "sub": "user-123",
  "scope": "weather:read"
}

the tool is excluded from tools/list.

The gateway logs show:

Client::"user-123" does not have the attribute `claimset_scope`

Expected behavior

multi_valued_claims should be honored for VirtualMCPServer the same way it is for thv run, MCPServer, and MCPRemoteProxy: principal.claimset_scope should be a Cedar Set (["weather:read"]) and the policy above should permit the call.

If the field is intentionally unsupported for vMCP, the operator should reject it or surface a status condition instead of silently dropping it.

Actual behavior

The field is parsed into cedar.ConfigOptions.MultiValuedClaims, but the vMCP path copies only an allow-list of fields and drops it:

  1. cmd/thv-operator/pkg/vmcpconfig/converter.go, resolveAuthzConfigRef: builds vmcpconfig.AuthzConfig from Policies, EntitiesJSON, GroupClaimName, RoleClaimName, and GroupEntityType only. The ConfigMap branch of convertAuthzConfig has the same omission.
  2. pkg/vmcp/config/config.go: AuthzConfig has no MultiValuedClaims field.
  3. pkg/vmcp/auth/factory/incoming.go: builds cedar.ConfigOptions without MultiValuedClaims, so the authorizer runs with it empty and never adds claimset_* attributes.

Environment (if relevant)

  • ToolHive version: vmcp:v0.49.0

Suggested direction

Plumb MultiValuedClaims through the vMCP path the same way GroupClaimName/RoleClaimName are:

  1. Add MultiValuedClaims []string to vmcpconfig.AuthzConfig.
  2. Copy opts.MultiValuedClaims in resolveAuthzConfigRef and in the ConfigMap branch of convertAuthzConfig.
  3. Pass it into cedar.ConfigOptions in pkg/vmcp/auth/factory/incoming.go.
    Optionally, update the docs to note which deployment modes support multi_valued_claims until this lands.

Activity

  1. Sanskarzz commented on Oct 4, 2026

    @Sanskarzz
    Collaborator

    Hi @lorenzozanee, thanks for raising the PR!

    Before starting work on an issue, please make sure it’s assigned to you first. Please leave a comment on the issue, and I can assign it to you.
    Please read CONTRIBUTING.md .

  2. suantea commented on Oct 11, 2026

    @suantea

    I've opened #6794 to plumb multi_valued_claims through the vMCP authz path (vMCP config + auth factory + operator converter). All targeted tests pass and build is clean.

  3. suantea commented on Oct 11, 2026

    @suantea

    Implemented in PR #6794 which also wires the OIDC transport flags and lockfile cleanup fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingneeds-triageIssue needs initial triage by a maintainer

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions