Skip to main content

Backstage Ships MCP Tokens for Claude and Cursor: What Exposing a Golden-Path IDP to AI Agents Actually Requires

8 min readDora NodaDora Noda
Share
On this page

A developer tells Claude Code: "spin up a new service using our golden-path template." Until recently, that sentence did nothing on its own — the agent had no way to reach into Backstage, your internal developer platform's software catalog and template engine, and actually invoke the scaffolder. Someone still had to open the UI, click through the wizard, and fill in the form by hand. Backstage 1.43 changes that: it ships experimental support for issuing an AI agent its own short-lived, per-user token, so Claude or Cursor can call your platform's own golden-path actions directly.

That's a genuinely new capability, not a chatbot bolted onto a dashboard. It's also a preview of a problem every self-hosted platform with a service registry — including one built for AI agents to deploy and operate apps — has to solve before an agent becomes a real actor on the platform: not just can the agent authenticate, but what, specifically, can it do once it has.


What actually shipped in 1.43

Backstage 1.43 introduces experimental Dynamic Client Registration (DCR) support for the platform's MCP integration. Concretely: the auth-backend can now issue a token on behalf of a specific user for consumption by an MCP client like Claude or Cursor, instead of requiring an administrator to hand every agent the same pre-shared secret. The Backstage team is explicit about where this stands — "highly experimental," and the issued tokens are valid for one hour only, with no refresh flow yet. It ships alongside smaller changes in the same release (OpenShift as a supported auth provider, a BACKSTAGE_ENV-aware config loader), but the MCP token work is the one asking for feedback on GitHub and Discord before it hardens into something teams should build on.

That timing lines up with a project already underway: the @backstage/plugin-mcp-actions-backend module, which turns entries in Backstage's ActionsRegistry — the same registry that backs Scaffolder templates — into callable MCP tools. Until 1.43, an agent could reach that registry, but only by authenticating as a generic, statically-configured client. What 1.43 adds is the missing piece: making that authentication per-user, so the platform can tell which human's agent did what.

How an agent reaches a golden-path action at all

The mcp-actions-backend plugin doesn't expose your whole Scaffolder catalog as one giant tool list by default. It's configured through mcpActions.servers in app-config.yaml, where each entry becomes a separate MCP endpoint scoped by an include/exclude filter using glob patterns on action IDs:

yaml
mcpActions:
  servers:
    scaffolder:
      name: "Backstage Golden Paths"
      filter:
        include:
          - id: "scaffolder:*"

That config stands up an endpoint at /api/mcp-actions/v1/scaffolder, and any Claude or Cursor session pointed at it (via a standard mcpServers block with a bearer token in the Authorization header) sees every action matching scaffolder:* as an invocable tool — named scaffolder.fetch-template, scaffolder.publish-github, scaffolder.catalog-register, and so on, prefixed by plugin ID to avoid collisions. Exclude rules take precedence over include rules, and an action needs to match at least one include rule to show up at all.

That filter is the entire safety boundary, and it's worth being concrete about what "the whole scaffolder:* namespace" actually contains. Backstage's built-in scaffolder actions include fetch:template (pull a skeleton and template variables into it), publish:github (create a real repository under your GitHub org, set the default branch, apply branch protection), catalog:register (register a catalog-info.yaml as a live entity in the software catalog), and github:actions:dispatch (trigger a workflow run on an existing repo). A team that reaches for scaffolder:* because it's the fastest way to "just expose the golden path" has, without meaning to, also handed an agent the ability to publish new repositories under the org, register catalog entities that didn't come through a reviewed template, or fire off arbitrary GitHub Actions runs on infrastructure that has nothing to do with the one template the human actually asked for. None of that requires a bug — it's exactly what the filter was configured to allow.

The fix isn't a smarter filter engine; it's a narrower one. A curated scaffolder-golden-path server that includes only scaffolder:fetch-template and scaffolder:catalog-register — the two actions a "create a new service from our approved template" workflow actually needs — gives an agent a tool it can't misuse into publishing arbitrary repos or dispatching arbitrary workflows, because those tools were never in its list to begin with. The MCP client can't call a tool the server never advertised. That's the concrete version of "curate a small set of actions" — not a best practice restated as advice, but the difference between an agent that can only walk the golden path and one that can also wander off it into publish:github on a bad day.

Two ways to authenticate that agent

Even with a curated action list, someone still has to answer "which agent is this, and for how long can it act." Backstage's mcp-actions-backend supports two distinct models today, and they trade off very differently:

Static bearer token (current default)Per-user DCR token (1.43, experimental)
SetupAdmin runs crypto.randomBytes(24).toString('base64'), hardcodes it in externalAccess configUser approves a popup in Backstage; auth-backend issues the token automatically
IdentityShared secret — every request looks like the same subject: mcp-clientsTied to the specific user who approved it
ExpiryWhatever the admin set, often effectively indefinite until manually rotated1 hour, hard-coded, no refresh yet
RevocationRotate the secret and redistribute it to every legitimate client at onceExpires on its own; no rotation coordination needed
Audit trail"an MCP client did this""this user's agent did this"

The static model is what almost every team runs today, and it's not a Backstage-specific shortcut — it's the industry norm. A March 2026 count of the public MCP server registry found roughly 3,012 unique servers listed, and only about 8.5% of them implement OAuth at all; the rest lean on static API keys, personal access tokens, or no authentication whatsoever. Backstage's experimental per-user, short-lived model is a small, unfinished feature — but it's already ahead of where most of the MCP ecosystem sits, because it at least makes "which human authorized this agent's action" answerable instead of "some client had the shared key."

What a self-hosted PaaS's own golden path needs to copy

A Cluster-API-managed platform whose bet is AI agents as first-class operators has the exact same shape of problem Backstage is previewing here — just with deploy and rollback in place of scaffolder:publish-github. The concrete checklist Backstage's design implies:

  • Issue tokens per identity, not per client. A shared static token for "the deploy MCP server" answers "was this request authenticated" but not "who authorized it" — the same gap Backstage's DCR work is closing for Scaffolder actions.
  • Default to short expiry, not administrator memory. A 1-hour token that nobody has to remember to rotate beats a static secret that's correct until someone forgets it's still live.
  • Split actions into scoped MCP servers, not one firehose. deploy and rollback and read logs are different blast radii; they belong in separately filtered endpoints an operator can grant independently, the same way a curated scaffolder-golden-path server should carry fetch-template and catalog-register but not publish-github.
  • Log the grant, not just the call. An audit trail that shows "user X approved agent Y's access at time Z" is what turns "an agent did something wrong" into a five-minute investigation instead of a platform-wide credential rotation.

None of this requires waiting for Backstage's feature to leave experimental status — it's a design constraint any MCP-exposing control plane can apply today, using whatever auth backend it already runs.

Backstage's own mcp-actions-backend also treats "who called what, and how long did it take" as a first-class signal rather than an afterthought — it's worth copying that instinct too. It exports mcp.server.operation.duration and mcp.server.session.duration as metrics, and every tools/call invocation gets its own OpenTelemetry trace span carrying the tool name, the plugin ID it belongs to, and the principal type (user, service, or none) that made the call. Payload capture — logging the actual arguments and results of a tool call — is opt-in and off by default, because an agent's deploy arguments can contain exactly the kind of sensitive configuration a platform shouldn't be writing into a trace store without an administrator deciding to. A deploy-authority MCP server that can't answer "which tool, which principal, how long, and was it a user or an unattended agent" for every call it served isn't ready to hold that authority in production, whether or not the token that authenticated the call was static or short-lived.

The honest caveat

This is not a feature to build a production dependency on yet. DCR itself is flagged by the Backstage team as likely to be superseded by Client ID Metadata Documents (CIMD) rather than hardened in place, the one-hour token has no refresh path, and the whole thing is explicitly asking for feedback before it stabilizes. Treat it as a preview of where IDP-to-agent authentication is heading, not a spec to copy verbatim. The part worth taking now isn't the DCR implementation — it's the two decisions it encodes: identity should travel with the token, and the token should expire whether or not anyone remembers to rotate it.

Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own, with an MCP surface built for an agent to be a first-class operator from day one, not a client holding a shared secret. Star the repo on GitHub or deploy your first app today.

Related articles

Give your agents a chain backend

Autonomous agents hit RPC endpoints very differently than people do. See what bex router handles on their behalf.

Read the agents guide