# Figma
> Adding Figma MCP to ivar.json, authenticating across providers, and handling allowlist requirements.
Source: https://ivar.run/docs/guide/mcp/integrations/figma

import { Callout } from 'fumadocs-ui/components/callout';

The Figma MCP integration connects your hall to Figma's official remote MCP endpoint (`https://mcp.figma.com/mcp`). Figma uses OAuth 2.0 authentication with server-side allowlists.

## 1. Add Figma to `ivar.json`

Add the canonical `figma` entry under `mcp` in your hall manifest:

```json title="ivar.json (mcp fragment)"
{
  "mcp": [
    {
      "name": "figma",
      "type": "http",
      "url": "https://mcp.figma.com/mcp"
    }
  ]
}
```

<Callout type="warn">
Figma MCP is OAuth-only and does not support Personal Access Token (PAT) authentication. The endpoint enforces a server-controlled redirect allowlist.
</Callout>

## 2. Sync provider configs

Run `ivar sync` to project the canonical `figma` definition into hall-qualified names (`acme-figma`) for your configured providers:

```bash
ivar sync
```

## 3. Authenticate

Authenticate Figma for a specific provider or across all configured providers in the hall:

```bash
# Authenticate for a single provider
ivar mcp auth figma --provider claude-code
ivar mcp auth figma --provider opencode
ivar mcp auth figma --provider omp

# Or authenticate for all configured providers in one step
ivar mcp auth figma --all-providers
```

### Expected provider behavior

| Provider | Mechanism | Behavior |
| --- | --- | --- |
| **Claude Code** | Provider-native OAuth | Claude Code manages its own OAuth lifecycle via `claude mcp login acme-figma`. Ivar does not preregister clients or manage tokens for Claude Code; credentials remain in Claude's internal credential store. |
| **OpenCode** | Ivar PKCE + credential store | OpenCode's dynamic client registration (DCR) is rejected by Figma's server allowlist. Ivar preregisters the client, runs an internal PKCE flow on loopback, and writes the resulting tokens into OpenCode's credential store (`mcp-auth.json`). |
| **OMP** | Ivar PKCE + `omp auth-broker` | Because OMP has no native MCP login CLI, Ivar performs prerequisite registration and internal PKCE, then imports the OAuth tokens into OMP's broker store keyed by profile and endpoint URL. |

## Generated OAuth metadata

When `ivar mcp auth` executes dynamic registration or endpoint discovery, it persists discovered client and endpoint metadata back to `ivar.json`:

```json title="Persisted oauth block in ivar.json (Generated)"
{
  "name": "figma",
  "type": "http",
  "url": "https://mcp.figma.com/mcp",
  "oauth": {
    "client_id": "<generated_client_id>",
    "client_secret_env": "IVAR_MCP_ACME_FIGMA_SECRET",
    "token_url": "<discovered_token_endpoint>",
    "resource": "<discovered_resource>"
  }
}
```

Client secrets are stored in `.ivar/secrets/mcp.env` and referenced by environment variable name (`client_secret_env`). Tokens are stored directly in provider credential stores.

## Client secret environment variable

### Secret origin

The secret is issued by Figma's dynamic client registration endpoint (`https://api.figma.com/v1/oauth/mcp/register`), called automatically by `ivar mcp auth figma` when the manifest entry has no `oauth` block. There is no Figma dashboard page to copy it from and no manual OAuth app to create.

The registration request sends:
- The allowlisted `client_name`
- The loopback redirect URI `http://127.0.0.1:19876/callback`
- `authorization_code` and `refresh_token` grant types
- The `code` response type
- `token_endpoint_auth_method: "none"`

Figma's response carries `client_id` (written to `ivar.json`) and a `client_secret` issued in practice despite requesting `none`. Ivar stores that secret in `.ivar/secrets/mcp.env` and uses `client_secret_post`, because Figma's token endpoint otherwise rejects the exchange with `Client secret is required`.

If the response carries no `client_secret`, the client stays public: no `client_secret_env` in `ivar.json` and no environment variable is required.

Registration is idempotent: an entry that already has `oauth` is never re-registered, so a second run never mints a new secret.

<Callout type="info">
The secret value exists only in `.ivar/secrets/mcp.env` on the machine that authenticated and is never committed. To recover it on a second machine, copy that line across from `.ivar/secrets/mcp.env`, or remove the `oauth` block from `ivar.json` and re-run `ivar mcp auth figma` to register a fresh client.
</Callout>

### Name derivation

Ivar derives the environment variable name from the hall-qualified server name. It converts ASCII alphanumeric characters to uppercase, folds all other characters to `_`, and wraps the result as `IVAR_MCP_<NAME>_SECRET`.

For example, the projected server `acme-figma` derives:

```text
IVAR_MCP_ACME_FIGMA_SECRET
```

`ivar.json` records only this variable name in `oauth.client_secret_env`. The secret value itself is never written to the manifest.

### Secret storage and file format

Secret values live in `<hall>/.ivar/secrets/mcp.env`. This file is gitignored by the root `.ivar/*` rule and written atomically with owner-only permissions (`0600` on Unix).

```bash title=".ivar/secrets/mcp.env"
# MCP client secrets managed by ivar
IVAR_MCP_ACME_FIGMA_SECRET="<client_secret>"
```

Format rules:
- One `KEY=VALUE` entry per line.
- Blank lines and `#` comments are ignored.
- Keys must be ASCII identifiers (letters, digits, underscores; cannot start with a digit).
- Values may be bare or double-quoted with JSON escaping. Ivar re-renders the file sorted by key with quoted, JSON-escaped values.
- The file is not shell-evaluated: do not use `export` or shell variable expansion.

### Resolution order

When resolving the secret, Ivar evaluates sources in order:

1. **Caller environment**: If the variable is present in the executing environment, Ivar uses that value and backfills it into `.ivar/secrets/mcp.env`.
2. **Secret file**: Otherwise, Ivar reads the value from `.ivar/secrets/mcp.env`.
3. **Missing secret**: If neither source defines the variable, execution halts with error code `mcp.missing_client_secret_env`. To resolve, export the variable (`export IVAR_MCP_ACME_FIGMA_SECRET=<client_secret>`) and re-run `ivar mcp auth`.

`ivar mcp auth figma` performs dynamic registration and persists the secret automatically. Manual edits to `mcp.env` are only needed during recovery—such as cloning a hall onto a new machine, rotating secrets, or supplying a secret that exists solely in your host environment.

### Provider consumption

| Provider | Reference format | Injection behavior |
| --- | --- | --- |
| **OpenCode** | `{env:IVAR_MCP_ACME_FIGMA_SECRET}` in `opencode.json` | `ivar session start` injects the resolved secret value directly into the OpenCode child process environment. |
| **OMP** | `${IVAR_MCP_ACME_FIGMA_SECRET}` in `mcp.json` | OMP resolves the variable from its runtime environment when starting the server. |
| **Claude Code** | None | Claude Code manages authentication in its own credential store and does not use this variable. |

## Troubleshooting

### Missing secret metadata

If `ivar sync` or provider startup fails with `mcp.missing_client_secret_env` or missing secret errors, verify that `.ivar/secrets/mcp.env` or your host environment defines the required variable. See [Client secret environment variable](#client-secret-environment-variable) above to configure the variable or re-run `ivar mcp auth figma`.

### Upstream allowlist or registration changes

Figma restricts OAuth redirects to approved callback URLs. If authentication fails during the browser handshake:
- Confirm that your loopback redirect URI matches Figma's permitted client ports (`http://127.0.0.1:19876/callback`).
- If Figma updates its upstream client registration policy, re-run `ivar mcp auth figma --provider <provider>` to refresh dynamic registration and token bindings. Check provider and CLI output for actionable diagnostics if upstream policy rejects the handshake.

## Next steps

- [Linear MCP integration](/docs/guide/mcp/integrations/linear) — Configure Linear issue tracking MCP.
- [MCP OAuth guide](/docs/guide/mcp/oauth) — Learn how Ivar manages secrets and credential lifecycles.
- [Provider guides](/docs/guide/mcp/providers/claude-code) — Detailed per-provider setup for Claude Code, OpenCode, and OMP.
- [MCP Reference](/docs/reference/mcp) — Complete specification of `ivar.json` MCP schemas.
