DocsFeaturesMCP Server

MCP Server

Lifecycle ships a built-in MCP server (Model Context Protocol — a standard way for AI assistants to call tools), so assistants like Claude Code, Cursor, VS Code, and Codex can look at your preview environments for you. Once connected, you can ask your AI tool things like:

  • “Is the environment for my PR up? What’s the frontend URL?”
  • “Why did the backend build fail in snowy-field-978044? Show me the logs.”
  • “List my environments and tell me which ones errored.”

The assistant answers by calling Lifecycle directly — no copy-pasting UUIDs, dashboards, or log snippets into the chat.

Looking for the opposite direction — connecting external MCP servers to Lifecycle’s built-in AI Agent? See MCP Integration.

Connect your AI tool

Your Lifecycle MCP URL is your Lifecycle app host plus /mcp — for example https://app.lifecycle.example.com/mcp. If your admin has enabled dynamic client registration, that URL is all you need — registration and login happen automatically. Otherwise (the default), you also need an OAuth client ID from your admin — see Without dynamic client registration.

Two prerequisites: your Lifecycle admin must have the MCP server enabled, and you need network access to your Lifecycle app host (e.g. VPN) — the same reachability as the Lifecycle UI.

The first time you connect, your browser opens your organization’s normal single sign-on page — the same login as the Lifecycle UI and lfc CLI — followed by a one-time consent screen. That’s it. When your session eventually expires, just run the client’s login step again.

Claude Code

Or run /mcp inside a session and pick lifecycle → Authenticate.

Cursor

Add the server to ~/.cursor/mcp.json (or per-project .cursor/mcp.json):

Cursor shows a Needs login prompt next to the server in Settings → MCP; clicking it opens the browser sign-in.

VS Code

Add the server to .vscode/mcp.json in your workspace (or your user-level mcp.json):

VS Code prompts you to trust and authenticate the server the first time Copilot Chat uses it.

Codex CLI

Add the server to ~/.codex/config.toml, then log in:

Try it with a prompt like “using the lifecycle tools, list my environments”. Every tool call runs under your identity — the same login as the Lifecycle UI — but note that this scopes filters, not visibility; see the note under What you can do.

What you can do

All v1 tools are read-only: your assistant can look things up, but it cannot deploy, redeploy, delete, or change environment variables from here — use the Lifecycle UI or the lfc CLI for those.

⚠️

Like the REST API and UI, any authenticated user can read any build, service, log, or site — myEnvironmentsOnly/mineOnly are convenience filters, not access controls. If a preview environment’s logs may contain sensitive output, treat them as visible to all authenticated Lifecycle users.

ToolWhat it answers
list_builds”What environments exist?” — searchable, pageable, with a my environments only filter
get_build”What’s the status of environment X?” — services, URLs, branch, and PR details for one build
list_services”Which services are in this environment, and where are they running?” — status, branch, image, URL
get_job_logs”Why did the build/deploy fail?” — build-job or deploy-job logs, live from the cluster or archived
list_sites”What static sites are published?”
get_site”Where is site X and when does it expire?”

It also exposes one MCP resource, lifecycle://builds/{uuid}, which returns a build’s detail document as JSON for clients that support attaching resources.

Tool reference

ToolParameters
list_buildssearch (string, optional) · myEnvironmentsOnly (boolean, optional) · page (int, optional) · limit (int, optional, default 25, max 100)
get_builduuid (string, required)
list_servicesuuid (string, required)
get_job_logsuuid (string, required) · service (string, required) · jobType (build | deploy, required) · jobName (string, optional — defaults to the most recent job) · tailLines (int, optional, default 200, max 2000)
list_sitesmineOnly (boolean, optional) · page (int, optional) · limit (int, optional, default 25, max 100)
get_sitesiteId (string, required)

How it works

A one-page tour for the curious:

  1. One endpoint on the web service. The MCP server is part of the Lifecycle web deployment, served over MCP’s Streamable HTTP transport at /mcp. There is nothing extra to run — it reads the same data the UI and API do, and it’s stateless, so it scales with your web replicas.

  2. Login is your normal SSO. Lifecycle’s Keycloak realm acts as the OAuth 2.1 authorization server. When a tool connects for the first time it discovers the auth settings automatically (via standard OAuth metadata), identifies itself to Keycloak — by registering itself when your admin has enabled dynamic client registration, or with the client ID your admin pre-registered — and sends you through the same browser single sign-on used by the UI and the lfc CLI. A one-time consent screen shows what the tool is asking for.

  3. Tokens only work here. Access tokens issued for the MCP server are bound to its exact URL (the OAuth audience). A CLI or UI token is rejected at /mcp, and an MCP token is rejected by the REST API — one leaked token never unlocks the other surface.

  4. Everything runs under your identity. Each tool call executes under the identity in your token, so filters like my environments only use your account — though, as in the UI, any authenticated user can read any environment (see What you can do). Tool output never includes service environment variables, which can contain secrets.

Setup (admins)

Enabling the MCP server for your Lifecycle deployment is two switches — one on the app, one on Keycloak.

Enable the endpoint on the web service

Set two environment variables on the Lifecycle web deployment:

MCP_RESOURCE_URL is the canonical URL clients will use — access tokens are audience-bound to this exact value, so it must match the resourceUrl you give Keycloak below, byte for byte (scheme, host, port, path). The endpoint is served only by the web process (LIFECYCLE_MODE web/all) and is absent unless MCP_SERVER_ENABLED is true.

Configure the Keycloak realm

The realm needs an mcp client scope (with audience and identity mappers) and, optionally, anonymous dynamic client registration so tools can self-register. The lifecycle-keycloak chart does this for you with an idempotent post-install/post-upgrade job:

The Job is idempotent and runs on both fresh installs and existing realms, so a Helm upgrade with these values is all that’s needed — no separate script to run by hand.

⚠️

All URLs listed (resourceUrl + extraAudiences) share a single token trust boundary — an access token issued for one is accepted by all of them. Use extraAudiences only for alternate URLs of the same deployment; do not use it to share one realm across production and staging.

Verify

should return the server’s OAuth metadata, and connecting any MCP client to https://app.lifecycle.example.com/mcp should walk you through browser login.

⚠️

Anonymous dynamic client registration is off by default and one-way to enable. It lets anyone who can reach your Keycloak host register an OAuth client (registering grants no access by itself — a real SSO login is still required for tokens), and turning it on deletes the realm’s anonymous Trusted Hosts policy, which cannot be undone by disabling the setting later. Only enable it (mcp.dcr.enabled: true in the chart, or --enable-anonymous-dcr with the script) when Keycloak is not reachable from the public internet. Otherwise leave it off and pre-register a client for your users, as described below. Back up the realm first if you may want to revert.

Without dynamic client registration

When dynamic client registration stays disabled (the default), pre-register one OAuth client in the Lifecycle Keycloak realm and distribute its client ID to your users:

  1. In the realm, create a public client (no client secret) with the Standard flow enabled and PKCE enforced (set Proof Key for Code Exchange Code Challenge Method to S256 in the client’s advanced settings).
  2. Turn on Consent required in the client’s settings, so users get the same one-time consent screen that dynamically registered clients show.
  3. Add the redirect URIs your users’ MCP clients need — CLI tools typically use a localhost callback such as http://localhost:8080/callback, while some editors use fixed HTTPS or app-scheme callbacks. Check each client’s documentation for its exact callback URL.
  4. Assign the mcp client scope to the client (as an optional client scope).
  5. Hand the client ID to your users.

Support for pre-registered client IDs varies by MCP client, so check your client’s documentation for its current state. At the time of writing:

  • Claude Code supports it — pass the ID and pin the callback port when adding the server, and register the matching http://localhost:8080/callback redirect URI in Keycloak:

  • Cursor supports it — add an auth object next to the server’s url in mcp.json with "CLIENT_ID": "<client-id>", and register Cursor’s fixed callbacks as redirect URIs: https://www.cursor.com/agents/mcp/oauth/callback (web/cloud agents) and cursor://anysphere.cursor-mcp/oauth/callback (desktop app).

  • VS Code and Codex CLI rely on dynamic client registration and do not currently document a way to supply a pre-registered client ID — consult their documentation for updates.

Troubleshooting

SymptomLikely cause
Client says the server needs authentication and nothing happensRun the client’s login step (claude mcp login …, codex mcp login …, or the login prompt in Cursor/VS Code settings)
Browser login loops or shows invalid_scopeThe Keycloak realm is missing the mcp client scope configuration — re-run the setup job or script
401 with a valid loginThe token audience doesn’t match MCP_RESOURCE_URL — make sure the URL configured in your client matches it exactly
Tools list is empty or calls fail after loginThe endpoint may be disabled (MCP_SERVER_ENABLED) on the web deployment
Registration rejectedDynamic client registration is disabled — the expected default. Use a pre-registered client ID (see Without dynamic client registration) or ask your Lifecycle admin