Skip to content

MCP Server Setup

Overview

The Floh MCP (Model Context Protocol) server exposes workflow management, run control, connector operations, and configuration tools to AI assistants like Claude and Cursor. Authentication uses Authifi OIDC tokens with RBAC-controlled scopes.

The resource server also checks the token's authorized party (azp / client_id). Documented MCP uses floh-mcp-client (MCP_SCOPES only). pnpm run setup-authifi-oidc-clients registers that confidential client. Do not set MCP process env to floh-client: a missing scope claim then authenticates with an empty permission set instead of 401. A console-session refresh token cannot be reused with floh-mcp-client.

Mutating MCP calls send Authorization: Bearer without a Floh session cookie, so they skip CSRF on /api.

Prerequisites

  • Running Floh server with OIDC configured in .env: OIDC_ISSUER and OIDC_CLIENT_ID. The MCP channel audience FLOH_MCP_AUDIENCE defaults to https://mcp.floh.api. (FLOH_RESOURCE_ID / OIDC_AUDIENCE is operator-tooling metadata and is not accepted as aud.)

FLOH_MCP_AUDIENCE must match on the API and the MCP process, or every MCP request fails with 401

The API builds its accepted-aud allow-list solely from FLOH_CONSOLE_AUDIENCE, FLOH_PORTAL_AUDIENCE, and FLOH_MCP_AUDIENCE. The MCP process sends FLOH_MCP_AUDIENCE as the RFC 8707 resource parameter on refresh, so Authifi mints the access token with the MCP channel identifier as aud. Both sides default to https://mcp.floh.api, and the MCP process prints a note on stderr when it uses the default. If you set the variable on one side, set the same value on the other; a mismatch starts cleanly and then rejects every MCP request. The default applies only to floh-mcp-client: with the floh-client rollback client and FLOH_MCP_AUDIENCE unset, the MCP process sends no resource, but a set value is still sent whichever client is configured.

The symptom is 401 Invalid token, not a 403: the audience check happens inside verifyToken(), and authenticate() catches that failure before the authorized-party check that produces 403 CHANNEL_DENIED is ever reached. A 401 here means the audience, not the credential.

  • Authifi tenant with admin access
  • Node.js 24+

1. Reconcile Authifi authorization

Floh manages three distinct Authifi resource servers: console, portal, and MCP. Set these non-secret identifiers, keeping every value different:

FLOH_CONSOLE_AUDIENCE=https://console-api.example.com
FLOH_PORTAL_AUDIENCE=https://portal-api.example.com
FLOH_MCP_AUDIENCE=https://mcp-api.example.com

The sync also needs gitignored .authifi-admin-token. Never put the token on the command line or commit it. The command loads repo .env when present, while direct shell values override file values. AUTHIFI_BASE_URL is derived from the token when unset. OIDC client setup uses the same token file. Preview the complete three-channel plan (the command rebuilds @floh/shared first):

pnpm run sync-authifi-rbac -- --dry-run

Dry-run is the default and performs no mutation. Review every create, update, link, unlink, and delete action. Apply interactively only after the preview:

pnpm run sync-authifi-rbac -- --apply

The command creates or updates each channel's resource server, permissions, access roles, groups, and relationships. It is safe to rerun; after apply, run the dry-run again and expect No changes. There is no production auto-apply in CI or deployment workflows.

Prune is optional and destructive. It removes only extra Floh-owned floh-console:, floh-portal:, and floh-mcp: children and managed permissions; resource servers and client assignments are never deleted:

pnpm run sync-authifi-rbac -- --apply --prune

Prune requires a second interactive confirmation. Reserve --yes for controlled non-interactive maintenance after its exact dry-run has been reviewed.

Next, reconcile the console, portal, and MCP OIDC clients against their matching channel resource servers. Existing-client reconciliation is additive: every registered callback and post-logout URI is preserved, including one from another environment sharing this tenant, except a callback whose parsed pathname is exactly /api/auth/callback or /api/auth/callback/. Pass the origins this invocation needs — they are appended to whatever the client already has, not substituted for it:

pnpm run setup-authifi-oidc-clients -- --tenant ls --yes --dry-run \
  --console-origin https://console.example.com \
  --portal-origin https://portal.example.com
pnpm run setup-authifi-oidc-clients -- --tenant ls --yes \
  --console-origin https://console.example.com \
  --portal-origin https://portal.example.com

The OIDC command's dry-run previews URI changes and verifies that the console, portal, and MCP resource servers each resolve uniquely with a positive numeric id. It cannot preview numeric client relationships before absent clients are created, so running the RBAC dry-run/apply first remains required. Every credentialed run resolves and confirms the target tenant, then setup removes managed sibling-channel links, binds each client only to its own channel resource server, and rereads the managed state before reporting success. The three channel identifiers must be pairwise distinct, and none may equal the token-derived AUTHIFI_ADMIN_RESOURCE.

Setup does not inspect or remove unrelated relationships. Pre-existing legacy transitional links remain untouched until the explicit cleanup under LSA-10182. Verify the three managed channel relations in Authifi after apply.

To roll back catalog changes, restore the previous catalog revision, preview with --dry-run --prune, then apply with --apply --prune. A normal apply leaves removed catalog entries in Authifi. Relationship removals happen before object deletion. Restore OIDC client URIs from the previous known-good origin list. The tooling does not delete resource servers or unrelated tenant objects.

All MCP access roles and groups remain namespaced under floh-mcp:. pnpm run setup-authifi-oidc-clients registers floh-mcp-client alongside the console and portal browser clients. DB RBAC and proprietary-token removal are LSA-9939, and runtime grant rechecks are LSA-9940.

2. Permission Reference

API Permissions (Scopes)

Permission Description
workflow:read List and view workflow definitions
workflow:create Create new workflow definitions
workflow:update Update draft workflow definitions
workflow:publish Publish workflows to active status
workflow:start Start new workflow runs
run:read List and view workflow runs
run:update Retry failed runs
run:cancel Cancel running workflows
connector:read List and view connectors
connector:manage Create, update, test, and execute connectors
project:read List projects and workflow sets
role_definition:read List role definitions
user:read List system users
group:read List user groups
schedule:read List scheduled triggers
config:export Export system configuration
config:import Import system configuration

Access Role Bundles

Access roles are namespaced under floh-mcp: in Authifi. Each has a matching group for user assignment.

Access Role Permissions
floh-mcp:reader workflow:read, run:read, connector:read, project:read, role_definition:read, user:read, group:read, schedule:read
floh-mcp:author Reader + workflow:create, workflow:update, workflow:publish, workflow:start, config:export
floh-mcp:operator All permissions

Tool-to-Scope Mapping

Tool Required Scope Destructive Requires Confirmation
list_workflows workflow:read no no
get_workflow workflow:read no no
validate_workflow workflow:read no no
generate_workflow_docs workflow:read no no
create_workflow workflow:create no no
update_workflow workflow:update no no
create_version workflow:create no no
publish_workflow workflow:publish yes yes
start_run workflow:start yes yes
list_runs run:read no no
get_run run:read no no
diagnose_run run:read no no
retry_run run:update no yes
cancel_run run:cancel yes yes
import_config config:import yes yes
export_config config:export no no
update_connector_script connector:manage yes yes
execute_connector_command connector:manage yes yes

3. Obtain a Refresh Token

The MCP server uses a refresh token minted for floh-mcp-client. A refresh token from a Floh console BFF session belongs to floh-client and will not authenticate against the MCP client.

Method 1: Authorization Code Flow

Request the offline_access scope during a direct OIDC authorization code flow against floh-mcp-client (placeholder callback https://localhost:4242) to receive a refresh token in the token response.

Method 2: Authifi Admin Tools

Use Authifi admin API or UI to issue a refresh token for a user on floh-mcp-client. Refer to Authifi docs for available endpoints.

4. Configure Claude Desktop

Build the MCP server

The Claude Desktop config points to the compiled dist/ output, so build first:

cd <path-to-repo>
pnpm --filter @floh/mcp build

Config file location

OS Path
macOS ~/Library/Application Support/Claude/claude_desktop_config.json
Windows %APPDATA%\Claude\claude_desktop_config.json
Linux ~/.config/Claude/claude_desktop_config.json

Add the floh MCP server

Merge the following into the mcpServers object in your config file:

{
  "mcpServers": {
    "floh": {
      "command": "node",
      "args": ["<path-to-repo>/packages/mcp/dist/index.js"],
      "env": {
        "FLOH_API_URL": "https://localhost:7070",
        "OIDC_ISSUER": "https://a-ci.ncats.io/_api/auth/ls",
        "OIDC_CLIENT_ID": "floh-mcp-client",
        "OIDC_CLIENT_SECRET": "<mcp-client-secret>",
        "FLOH_MCP_AUDIENCE": "https://mcp.floh.api",
        "FLOH_REFRESH_TOKEN": "<your-refresh-token>",
        "NODE_EXTRA_CA_CERTS": "<path-to-repo>/certs/localhost.crt"
      }
    }
  }
}

Environment variables

Variable Required Description
FLOH_API_URL yes Base URL of the Floh API server
OIDC_ISSUER yes Authifi OIDC issuer URL (e.g. https://a-ci.ncats.io/_api/auth/ls)
OIDC_CLIENT_ID yes MCP client id (floh-mcp-client). Process env; MCP_OIDC_CLIENT_ID wins if both are set
OIDC_CLIENT_SECRET no MCP client secret (MCP_OIDC_CLIENT_SECRET preferred; from env/mcp.env, not console)
FLOH_MCP_AUDIENCE no MCP RS id sent as RFC 8707 resource on refresh; default https://mcp.floh.api
FLOH_REFRESH_TOKEN yes Refresh token minted for floh-mcp-client (see Section 3)
NODE_EXTRA_CA_CERTS no Path to TLS certificate file — needed for local dev with self-signed certs

Replace <path-to-repo> with the absolute path to your Floh repository clone.

Verification

  1. Restart Claude Desktop (quit fully and reopen)
  2. Look for "floh" in the MCP server list (hammer icon in the chat input)
  3. Try a read-only tool: ask Claude to "list my Floh workflows"
  4. If the server fails to start, check ~/Library/Logs/Claude/mcp*.log for error details

5. Configure Cursor IDE

Add to .cursor/mcp.json in the workspace root:

{
  "mcpServers": {
    "floh": {
      "command": "npx",
      "args": ["tsx", "packages/mcp/src/index.ts"],
      "env": {
        "FLOH_API_URL": "https://localhost:7070",
        "OIDC_ISSUER": "https://a-ci.ncats.io/_api/auth/ls",
        "OIDC_CLIENT_ID": "floh-mcp-client",
        "OIDC_CLIENT_SECRET": "<mcp-client-secret>",
        "FLOH_MCP_AUDIENCE": "https://mcp.floh.api",
        "FLOH_REFRESH_TOKEN": "<your-refresh-token>",
        "NODE_EXTRA_CA_CERTS": "<path-to-repo>/certs/localhost.crt"
      }
    }
  }
}

6. Tool Confirmation Behavior

Destructive tools (publish, start, cancel, import, update connector scripts, execute commands) require explicit confirmation before execution. When called without confirmed: true, they return a preview of what will happen.

The AI assistant will present this preview to you and ask for confirmation before re-calling the tool with confirmed: true.

7. Security Notes

  • Refresh tokens are long-lived — store them securely (environment variables, secret managers). Never commit them to version control.
  • Token rotation: If Authifi rotates the refresh token, the MCP server stores the new one in memory automatically.
  • Access tokens are short-lived (typically 1 hour), cached in memory only, and refreshed automatically.
  • Audit trail: All MCP actions are recorded in the Floh audit log with the user's identity.
  • Authorization: Floh derives the caller's permissions entirely from the access token's scope claim. Authifi controls which scopes are issued, based on the user's group/role assignments there — Floh keeps no parallel permission store.

8. Troubleshooting

Error Cause Fix
"Invalid or expired token" on every call Static floh_* API token (no longer supported) Switch to OIDC refresh token auth
"Token refresh failed: 400" Refresh token expired or revoked Obtain a new refresh token
"OIDC discovery failed" OIDC_ISSUER URL unreachable Check network and issuer URL
"Permission denied" User lacks required scope Add user to appropriate floh-mcp:* group in Authifi
"CONFIRMATION REQUIRED" Destructive tool needs confirmed: true Normal behavior — confirm the action