Skip to content

github-issue demo: make the production github-tool-mcp reachable by token-exchange-aiac #1540

Closed

Description

@anatolykoyfman

Background

cortex #1496 added token-exchange-aiac, an outbound token exchange with no routes. It derives the audience from the destination host (spiffe://<td>/ns/{namespace}/sa/{service} for operator-registered workloads) and requests no scope, so a target is granted to a caller only by a default client scope of the caller's client.

rossoctl/aiac#242 moves the AIAC demo's github-agent to that plugin and drops authproxy-routes. The agent calls the production GitHub tool of this repo's github-issue demo at MCP_URL=http://github-tool-mcp:9090/mcp. The route that used to map that host is gone:

- host: "github-tool-mcp"
  target_audience: "github-tool"
  token_scopes: "openid github-tool-aud github-full-access"

Under token-exchange-aiac those calls are not exchanged: the derived audience spiffe://<td>/ns/team1/sa/github-tool-mcp names no Keycloak client, so the call passes through with the caller's token. And no token carries github-full-access, so the tool always uses its public PAT.

Why the demo does not fit the plugin

demos/github-issue/k8s/github-tool-deployment.yaml and demos/github-issue/setup_keycloak.py:

  1. No client the host derives. The tool's Service is github-tool-mcp, but it runs under the default ServiceAccount, and its Keycloak client is a plain github-tool that setup_keycloak.py creates by hand. The plugin's SPIFFE form needs Service name == ServiceAccount name == the last path segment of the client ID.
  2. Not enrolled. The tool has no AgentRuntime CR and no AuthBridge sidecar, so the operator registers no client for it.
  3. Optional scopes. setup_keycloak.py makes github-tool-aud and github-full-access realm optional scopes and links them to the agent as optional. The plugin sends no scope, so an optional scope is never applied.
  4. The name github-tool is taken in AIAC's demo. AIAC's UC-1 stub tool runs as Service = ServiceAccount = github-tool in team1, so the production tool cannot take that name.

Task

Make the production tool reachable by token-exchange-aiac under its existing Service name github-tool-mcp, so that the AIAC agent's unchanged MCP_URL is exchanged:

  • Give the tool Deployment a ServiceAccount named github-tool-mcp (equal to its Service), and enroll it (an AgentRuntime CR, type tool) so the operator registers the client spiffe://<td>/ns/team1/sa/github-tool-mcp and its audience scope agent-team1-github-tool-mcp-aud.
  • The tool reads only the scopes of the token today (REQUIRED_SCOPE), so its AUDIENCE env is unused; set it to the new client ID or drop it, and say which in the manifest.
  • In setup_keycloak.py, stop creating the hand-made github-tool client and github-tool-aud scope for this path, and make github-full-access grantable as a default scope of the caller (not a realm default, so it does not reach every client).
  • Decide how the alice/bob split works without a requested scope. With default scopes, every token the agent exchanges carries github-full-access; the demo currently gives it only to a token that requests it.
  • Update demo-ui.md, demo.md and demo-aiac.md (they describe the route and the optional scopes).

AIAC's side (rossoctl/aiac#242): its WIRE step links the tool's audience scope agent-team1-github-tool-mcp-aud as a default scope of github-agent when it exists, and the agent's MCP_URL already targets github-tool-mcp. It does not link github-full-access: as a default scope it would be in every token github-agent exchanges, so every user would get the privileged PAT. That is the open question of the alice/bob item above: token-exchange-aiac requests no scope, so a per-user grant needs another mechanism (for example a scope mapped from a user role, or the tool choosing the PAT from the user rather than a token scope).

Acceptance criteria

  • With the tool deployed from this demo and AIAC's WIRE run, a tools/call from the AIAC github-agent to github-tool-mcp:9090/mcp is exchanged: the tool receives a token whose aud is spiffe://<td>/ns/team1/sa/github-tool-mcp.
  • The privileged PAT is chosen per user, not per agent: a user granted full access gets it, others get the public PAT. A default github-full-access on the agent's client does not meet this.
  • No authproxy-routes and no realm default scope are added.
  • The demo docs describe the new wiring.

Tracked on the AIAC side by rossoctl/aiac#247.

Activity

  1. huang195 commented on Oct 29, 2026

    @huang195
    Member

    Closing for now: this is specific to the Kubernetes / envoy-sidecar / SPIRE deployment path. Current prioritization is the laptop install; K8s and envoy-sidecar remain supported targets but are not priority. Reopen when that work resumes.

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

    aiacAIAC team workbugSomething isn't working

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions