Skip to main content
Glama
Featureflip

Featureflip

Official

@featureflip/mcp

MCP (Model Context Protocol) server for Featureflip — manage feature flags from AI coding assistants (Claude Code, Cursor, Copilot, Cline) and autonomous agents.

Setup

  1. Create an API token in the Featureflip dashboard:

    • Personal token (ffp_...): Settings → API Tokens — acts as you, for interactive editor use.

    • Service token (ffs_...): Organization Settings → Service Tokens — scoped machine identity for CI/agents.

  2. Add the server to your MCP client:

Claude Code

claude mcp add featureflip -e FEATUREFLIP_TOKEN=ffp_your_token -- npx -y @featureflip/mcp@latest

Cursor / Cline / generic JSON config

{
  "mcpServers": {
    "featureflip": {
      "command": "npx",
      "args": ["-y", "@featureflip/mcp@latest"],
      "env": { "FEATUREFLIP_TOKEN": "ffp_your_token" }
    }
  }
}

Keep the @latest. Without a version, npx reuses the copy it downloaded the first time and never checks npm again, so tools added in later releases would never show up in your client.

Related MCP server: Featureflow MCP Server

Configuration

Env var

Required

Default

Purpose

FEATUREFLIP_TOKEN

yes

—

ffp_/ffs_ API token

FEATUREFLIP_API_URL

no

https://api.featureflip.io

API base URL

FEATUREFLIP_ORG

no

auto

Org slug (needed only for multi-org personal tokens)

Tools

CRUD: list_projects, list_environments, list_flags, get_flag, create_flag, update_flag, delete_flag, archive_flag, restore_flag, set_flag_expiry, set_flag_owner, set_flag_permanent, toggle_flag, update_flag_environment_config, copy_flag_config, get_targeting, update_targeting, manage_targeting_rule, manage_variation, list_segments, get_segment, manage_segment, manage_project, set_default_flag_lifetime, manage_environment, list_sdk_keys, manage_sdk_key, list_flag_triggers, manage_flag_trigger

Webhooks (Admin token required): list_webhooks, list_webhook_deliveries, manage_webhook, deliver_webhook

Workflows: flag_status (cross-environment view), flag_evaluations (what a flag served in one environment: evaluation counts by variation and rule), compare_environments (which flags differ between two environments), find_stale_flags (cleanup candidates), list_removal_candidates (flags safe to remove, with the prerequisite dependents to remove first), wrap_feature (create flag + get the SDK snippet for your language)

Full reference: https://featureflip.io/docs/integrations/mcp/

Notes

  • Flag evaluation is not exposed over MCP — use the language SDKs in application code.

  • Every mutation is audit-logged and attributed to the token.

License

Apache-2.0

Available Tools

39 tools
archive_flagArchive feature flagA
Destructive

Archive a flag (soft-hide, evaluation stops serving it). Reversible with restore_flag. Archive dependents first: refused with FLAG_HAS_DEPENDENTS while another live flag lists this one as a prerequisite, so archive those flags (blockedBy in find_stale_flags / list_removal_candidates) first. Refused with FLAG_RECENTLY_EVALUATED while live traffic is still evaluating the flag, because archiving makes every caller fall back to its own hardcoded default — normally that means the code removal has merged but not deployed yet, and the refusal clears itself once it has.

Inputs: flag (required), project (required), force, reason. Returns: flag, archived

compare_environmentsCompare environmentsA
Read-only

Compare flag configuration between two environments: which flags differ and in which sections (state, defaultVariation, strategy, rules, prerequisites). Returns only differing flags unless different_only is false. To see exactly what would change for one flag, preview copy_flag_config (Team plan and above, Member role).

Inputs: base (required), other (required), project (required), tag, +4 more. Returns: A page of results plus an opaque cursor for the next page, or null when this is…

copy_flag_configCopy flag config between environmentsA
Destructive

Copy one flag's targeting (default variation, strategy, rules, prerequisites) from one environment into another. On/off is copied only with include_state: true. Previews by default (dry_run: true) and changes nothing; review before/after, changedSections and warnings, then call again with dry_run: false plus the preview's sourceETag and targetETag as source_etag/target_etag to apply. If the apply is refused with 412, something changed since the preview: preview again. Applying needs both ETags, and the same source and include_state as the preview (the ETags record environment state, not the request). Team plan and above.

Inputs: flag (required), source (required), target (required), project (required), +5 more. Returns: Response of `POST .../flags/{flag}/environments/{env}/copy`, for a dry run and…

create_flagCreate feature flagA

Create a feature flag. type is one of Boolean|String|Number|Json. Boolean flags get true/false variations automatically; for other types pass initialVariations. The flag is created in every environment of the project (disabled).

Inputs: key (required), name (required), type (required), project (required), +8 more. Returns: Public detail representation of a feature flag, returned by `GET .../flags/{fla…

delete_flagDelete feature flagA
Destructive

PERMANENTLY delete a flag across all environments. Fails with FLAG_HAS_DEPENDENTS if other flags use it as a prerequisite. Prefer archive_flag unless the flag must be fully removed.

Inputs: flag (required), project (required), reason. Returns: deleted

deliver_webhookSend a test event or redeliverA

action=test queues one synthetic flag.toggled event to this subscription alone; action=redeliver (deliveryId from list_webhook_deliveries) re-sends a finished delivery, restarting its retry schedule. Delivery is asynchronous: read list_webhook_deliveries for the outcome. Both are refused for a disabled subscription, and redeliver for a delivery that is still Pending. Requires an Admin token. A 404 on every webhook call means webhooks are not enabled for the organization.

Inputs: id (required), action (required), deliveryId. Returns: object

find_stale_flagsFind stale flagsA
Read-only

Find flags that look ready for code cleanup: not updated in N days AND either enabled in every environment (verify rollout is complete before removing — per-rule percentage ramps are not inspected) or disabled in every environment (dead — remove flag and code path). A flag whose expiry date (set_flag_expiry) has passed is always a candidate, however recently it was edited; if it is on in some environments and off in others its reason is past-expiry, meaning the owner has to decide which way to fold it. A project can give its temporary flags a default lifetime, so a flag with no date of its own can still be past expiry. Every result carries expiresAtUtc (the date set on the flag), effectiveExpiresAtUtc (the date in effect, from the flag or its project default), expirySource (explicit, project-default, or null), expired and owner (null when unowned). Flags marked permanent (kill switches, ops toggles) are never listed. Pass owner to see one person's stale flags ("me" for your own) or "none" for the unowned ones. Every result also carries blockedBy: the live flags that still list it as a prerequisite, which have to be removed and archived before it ([] when none). blockedBy is null when the server did not classify the flag as a removal candidate, which means unknown, not unblocked. A flag that other live flags list as a prerequisite has to be removed LAST, dependents first: archiving it while a dependent still names it makes that dependent fail its prerequisite check and serve its off variation, so archive_flag refuses it with FLAG_HAS_DEPENDENTS. Checks at most 50 candidates per call, expired flags first.

Inputs: project (required), days, owner. Returns: note, owner, stale, checked, +4 more

flag_evaluationsFlag evaluations in environmentA
Read-only

What a flag actually served in ONE environment over the last 7, 30 or 90 days: total evaluations, the split by variation, and which rule (or fallthrough, off, prerequisite, error) served what. Percentage-rollout rules include their configured weights and a sample-ratio check; rollout.flagged=true means the served split is statistically off the configured weights. A live rollout rule is always listed, with count 0 and no variations when it served nothing. rollout.unreached is set when a live rollout rule got no evaluations while the flag's rules got 100 or more: usually the context lacks rollout.bucketBy, or an earlier rule or the conditions catch the traffic. These are evaluation counts, NOT unique users. Counts come from SDK-reported events, so zero means no evaluations were reported, not necessarily no traffic.

Inputs: flag (required), project (required), environment (required), days. Returns: What a flag served in one environment over the window, returned by `GET .../fla…

flag_statusFlag status across environmentsA
Read-only

Compact cross-environment view of one flag: enabled state, strategy, default variation, and prerequisites per environment.

Inputs: flag (required), project (required). Returns: key, name, type, archived, +2 more

get_flagGet feature flagA
Read-only

Get one feature flag with its variations and metadata, including its owner (null when unowned). Address by flag key or id.

Inputs: flag (required), project (required). Returns: Public detail representation of a feature flag, returned by `GET .../flags/{fla…

get_segmentGet user segmentB
Read-only

Get one user segment (its conditions, id, and metadata) by key or id.

Inputs: project (required), segment (required). Returns: Public representation of a user segment, returned by `GET .../segments`, `GET .…

get_targetingGet targeting rulesA
Read-only

Get a flag's current targeting configuration (enabled flag + ordered rules) in one environment.

Inputs: flag (required), project (required), environment (required). Returns: The full targeting configuration for a flag in a single environment, returned b…

list_environmentsList environmentsA
Read-only

List the environments of a project (e.g. development, staging, production).

Inputs: project (required), limit, cursor. Returns: A page of results plus an opaque cursor for the next page, or null when this is…

list_flagsList feature flagsA
Read-only

List feature flags in a project. Filter with search (key/name substring), tag, type, archived, owner. Each flag carries its owner ({id, email, name}, or null when unowned). Paginated via cursor.

Inputs: project (required), tag, type, limit, +4 more. Returns: A page of results plus an opaque cursor for the next page, or null when this is…

list_flag_triggersList flag triggersA
Read-only

List a flag's triggers in one environment, or get one by passing trigger: id, name, action (Enable or Disable), whether each is enabled, the last four characters of its secret, and when it last fired. A trigger is a secret URL that a monitoring tool (a Grafana alert, a Datadog monitor) calls to turn the flag on or off. The URL is never listed; it is shown once, when manage_flag_trigger creates or rotates it.

Inputs: flag (required), project (required), environment (required), limit, +2 more. Returns: object

list_projectsList projectsA
Read-only

List projects in the Featureflip organization. Paginated: pass cursor from next_cursor to continue.

Inputs: limit, cursor. Returns: A page of results plus an opaque cursor for the next page, or null when this is…

list_removal_candidatesList removal candidatesA
Read-only

List the flags the server is confident can be removed from code, the same list the Featureflip flag cleanup GitHub Action works from. Each item has key, reason, status (Dead or Stale), treatment (true = keep the on-branch, false = keep the off-branch) and blockedBy: the live flags that still list it as a prerequisite. Only remove a flag whose blockedBy is empty. A flag that other live flags list as a prerequisite has to be removed LAST, dependents first: archiving it while a dependent still names it makes that dependent fail its prerequisite check and serve its off variation, so archive_flag refuses it with FLAG_HAS_DEPENDENTS. staleness "dead" (the default) returns only dead flags, "stale" adds stale ones. Paginated via cursor.

Inputs: project (required), limit, cursor, staleness. Returns: A page of results plus an opaque cursor for the next page, or null when this is…

list_sdk_keysList SDK keysA
Read-only

List the SDK keys of one environment: id, name, type, last four characters, and whether each is active. The full key is never listed; it is shown once, when manage_sdk_key creates it.

Inputs: project (required), environment (required), limit, cursor. Returns: A page of results plus an opaque cursor for the next page, or null when this is…

list_segmentsList user segmentsA
Read-only

List reusable user segments in a project. Segments are referenced from targeting rules via userSegmentId.

Inputs: project (required), limit, cursor. Returns: A page of results plus an opaque cursor for the next page, or null when this is…

list_webhook_deliveriesList webhook deliveriesA
Read-only

List one subscription's delivery attempts, most recent first. status is Pending (awaiting an attempt, backing off, or in flight), Succeeded or DeadLettered; lastResponseStatusCode and lastError explain a failure. Paginated via cursor. Requires an Admin token. A 404 on every webhook call means webhooks are not enabled for the organization.

Inputs: id (required), limit, cursor. Returns: A page of results plus an opaque cursor for the next page, or null when this is…

list_webhooksList webhook subscriptionsA
Read-only

List the organization's outbound webhook subscriptions (url, event/project/environment filters, enabled state, failure count, signing secret ids — never secret values), plus availableEventTypes: the event types a subscription can filter on. Empty filter lists mean "all". Paginated via cursor. Requires an Admin token. A 404 on every webhook call means webhooks are not enabled for the organization.

Inputs: limit, cursor. Returns: A page of results plus an opaque cursor for the next page, or null when this is…

manage_environmentCreate or update an environmentA
Destructive

Create an environment in a project, or change its name, color or sort order. action=create needs key + name; action=update needs environment and changes only the fields you pass. The key is immutable. Environments cannot be deleted from here. require_change_reason makes every write to the environment need a reason, and require_confirmation makes the dashboard ask for confirmation first; omit either on update to leave it unchanged. Turning either off needs an Admin or Owner token and a reason. A new environment needs an SDK key before apps can use it (manage_sdk_key).

Inputs: action (required), project (required), key, name, +6 more. Returns: object

manage_flag_triggerCreate, update, rotate, or delete a flag triggerA
Destructive

Manage a flag's triggers in one environment. A trigger is a secret URL a monitoring tool POSTs to (no body) to turn the flag on (Enable) or off (Disable); calling it when the flag is already in that state changes nothing. action=create needs name + triggerAction and returns the URL ONCE. action=update needs trigger and changes only the fields you pass (name, description, enabled; enabled=false stops the URL working until re-enabled). action=rotate needs trigger: the old URL stops working at once and the new one is returned ONCE. action=delete needs trigger. The action (Enable/Disable) is fixed at creation. Creating, re-enabling and rotating need the Team plan or above; every write needs a Member token; at most 10 per flag per environment. To change the flag yourself, use toggle_flag instead.

Inputs: flag (required), action (required), project (required), environment (required), +7 more. Returns: object

manage_projectCreate or update a projectA
Destructive

Create a project, or change its name/description. action=create needs key + name; action=update needs project and changes only the fields you pass (description: "" clears it). The key is immutable. Projects cannot be deleted from here.

Inputs: action (required), key, name, project, +1 more. Returns: object

manage_sdk_keyCreate, rename, or revoke an SDK keyA
Destructive

Manage an environment's SDK keys. action=create needs name + type and returns the full key ONCE (ServerSide for backend SDKs, ClientSide for browser/mobile). action=rename needs sdkKey and changes only the fields you pass. action=revoke needs sdkKey and stops the key working immediately; apps still using it lose flag updates; revoking a critical environment's key needs a reason. To rotate: create a new key, deploy it, then revoke the old one.

Inputs: action (required), project (required), environment (required), name, +4 more. Returns: object

manage_segmentCreate, update, or delete a user segmentA
Destructive

Manage reusable user segments, which targeting rules reference by userSegmentId. action=create needs key + name (+ conditions); action=update needs segment and changes only the fields you pass (conditions replaces the whole list; description: "" clears it); action=delete needs segment. On update, pass ifMatch (the etag from get_segment) so a change someone made since you read it is not overwritten. ifMatch is rejected on create and delete: the API cannot make those conditional.

Inputs: action (required), project (required), key, name, +5 more. Returns: object

manage_targeting_ruleAdd, update, remove, or reorder one targeting ruleA
Destructive

Edit a single targeting rule instead of replacing them all with update_targeting. action=add needs rule (appended last); action=update needs ruleId + rule and changes only the fields you pass (conditionGroups replaces the rule's groups; to clear rolloutPercentage or userSegmentId use update_targeting); action=remove needs ruleId; action=reorder needs ruleIds, every existing rule id exactly once, in the new order. Rule ids come from get_targeting.

Inputs: flag (required), action (required), project (required), environment (required), +4 more. Returns: object

manage_variationAdd, update, or remove a variationA
Destructive

Manage a flag's variations. action=add requires key + value; action=update/remove require variationId (get ids via get_flag). Removing a variation fails with VARIATION_HAS_DEPENDENTS if other flags depend on it.

Inputs: flag (required), action (required), project (required), key, +5 more. Returns: object

manage_webhookCreate, update, or delete a webhook subscription, or rotate its secretA
Destructive

action=create requires name + url and returns the signing secret. action=update/delete/rotate_secret/retire_secret require id. provider (create only, default GenericHttp) is the destination type: a Slack incoming webhook URL (https://hooks.slack.com/services/...) needs provider: "Slack", which posts readable channel messages; provider: "Datadog" sends Events API change events (url is your site's https://event-management-intake./api/v2/events) and provider: "Grafana" creates annotations (url is https:///api/annotations). Datadog and Grafana require credential (a Datadog API key, or a Grafana service account token that can create annotations, e.g. Editor); GenericHttp and Slack refuse it. credential is write-only: stored encrypted, never returned, and never echoed in this tool's output. A subscription's provider can never change. update changes only the fields you pass and keeps the rest; pass an empty list to widen that filter back to "all". projects take project keys or ids; environments take "/" keys (e.g. "web/production") or ids. eventTypes come from list_webhooks → availableEventTypes. create and rotate_secret return a secret that is NEVER shown again: relay it to the user verbatim so they can store it (for a GenericHttp subscription only: Slack, Datadog and Grafana never check it, so skip it there). Slack doesn't verify signatures, so a Slack subscription's secret is unused and rotate_secret is refused for one, and so are Datadog and Grafana ones, which authenticate with credential instead. On update, omit credential to keep the stored one; changing the url of a Datadog or Grafana subscription requires sending credential again. rotate_secret adds a new active secret while the old one keeps signing; retire_secret (secretId from list_webhooks) removes one and is refused for the last active secret. A project-restricted service token must list at least one project, all in its scope. Requires an Admin token. A 404 on every webhook call means webhooks are not enabled for the organization.

Inputs: action (required), id, url, name, +8 more. Returns: object

restore_flagRestore archived flagB

Restore a previously archived flag.

Inputs: flag (required), project (required), reason. Returns: flag, archived

set_default_flag_lifetimeSet or remove a project's default flag lifetimeA
Idempotent

Set how many days a temporary flag with no expiry date of its own lives before it counts as expired, or pass days: null to remove the default. Advisory only: evaluation never changes. Pass preview: true first to see how many flags would newly be, or stop being, past expiry without changing anything. Setting a value is refused with FEATURE_NOT_ENABLED when the organization's plan lacks it; removal is always allowed. The current value is defaultFlagLifetimeDays in list_projects.

Inputs: days (required), project (required), preview. Returns: applied, project, newlyPastExpiry, noLongerPastExpiry, +1 more

set_flag_expirySet or clear flag expiryA
Idempotent

Set the date a flag is expected to be removed by, or pass expiresAtUtc: null to clear it. Expiry is advisory: evaluation never changes. Once the date passes, find_stale_flags reports the flag as expired. expiresAtUtc takes a date (2026-12-31), which means the end of that day in UTC, the same as picking it in the dashboard, or a full ISO-8601 timestamp, which is stored exactly. Refused with EXPIRY_IN_PAST for a time that has already passed (today's date is allowed), with FEATURE_NOT_ENABLED while flag expiration is not enabled for the organization, and with PERMANENT_FLAG_HAS_EXPIRY on a permanent flag (make it temporary first with set_flag_permanent). Clearing is always allowed.

Inputs: flag (required), project (required), expiresAtUtc (required). Returns: flag, project, expiresAtUtc

set_flag_ownerSet or clear flag ownerA
Idempotent

Name the person responsible for a flag, or pass owner: null to leave it unowned. owner is the email of an active member of the organization, or "me" for the token's own user (needs a personal access token). The owner gets the flag's cleanup notices; evaluation never changes. Refused with OWNER_NOT_MEMBER for an email that is not an active member, and with PLAN_FEATURE_UNAVAILABLE below the Pro plan. Clearing is always allowed.

Inputs: flag (required), owner (required), project (required). Returns: flag, owner, project

set_flag_permanentMark a flag permanent or temporaryA
Idempotent

Mark a flag permanent (a kill switch, ops toggle or entitlement gate that is meant to stay), or pass permanent: false to make it temporary again. Permanent flags are never listed as removal candidates or by find_stale_flags; evaluation never changes. Marking is refused with PERMANENT_FLAG_HAS_EXPIRY while the flag has an expiry date (clear it first with set_flag_expiry and expiresAtUtc: null), with FEATURE_NOT_ENABLED while permanent flags are not enabled for the organization, and on an archived flag. Making a flag temporary is always allowed.

Inputs: flag (required), project (required), permanent (required). Returns: flag, project, permanent

toggle_flagToggle flag in environmentA
Destructive

Enable or disable a flag in ONE environment. Affects live evaluation immediately — double-check the environment.

Inputs: flag (required), enabled (required), project (required), environment (required), +1 more. Returns: flag, enabled, project, environment

update_flagUpdate feature flag metadataA
Destructive

Update flag name/description/tags/clientSideVisible. Changes only the fields you pass and keeps the rest; changing clientSideVisible needs a reason when any environment of the project is critical. pass description: "" to clear it. Key and type are immutable. Use toggle_flag / update_targeting for behavior changes. Pass ifMatch (the etag from get_flag) to refuse the write if the flag changed since you read it.

Inputs: flag (required), project (required), name, tags, +4 more. Returns: etag, flag, project, updated

update_flag_environment_configUpdate flag environment configA
Destructive

Update a flag's per-environment serving config: defaultVariationId (served on fallthrough, required), strategy (SingleVariation | PercentageRollout | TargetedRollout — only SingleVariation is currently supported at the environment level), and prerequisites. Percentage rollouts are configured on targeting rules via update_targeting.

Inputs: flag (required), project (required), environment (required), defaultVariationId (required), +3 more. Returns: flag, project, strategy, environment, +2 more

update_targetingReplace targeting rulesA
Destructive

REPLACE all targeting rules of a flag in one environment (full PUT — rules not included are removed). Rules are evaluated in order. Get the current rules first with get_targeting. Pass ifMatch (the etag from get_targeting) so rules someone else changed meanwhile are not overwritten.

Inputs: flag (required), rules (required), project (required), environment (required), +2 more. Returns: etag, flag, project, environment, +1 more

wrap_featureWrap a feature in a new flagA

Create a Boolean feature flag and get back the SDK code snippet to guard the new code path with it. Returns the snippet only — apply the edit yourself. The flag starts DISABLED in every environment; enable it with toggle_flag when ready.

Inputs: key (required), project (required), language (required), name, +3 more. Returns: flag, next_steps, integration

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

    TDQS

    A3.7/5.0

    Scored across 39 tools

    Disambiguation4/5

    Most tools target distinct resources and actions, and the descriptions clarify many potential overlaps. Boundaries are somewhat blurry among update_flag_environment_config, update_targeting, manage_targeting_rule, and toggle_flag, and between compare_environments/copy_flag_config/flag_status, plus find_stale_flags/list_removal_candidates.

    Naming Consistency4/5

    The set mostly follows a readable snake_case convention with verb_noun names such as list_flags, create_flag, toggle_flag, and archive_flag. Minor deviations appear in noun-first names like flag_status and flag_evaluations, and in multi-action manage_* tools, but the pattern remains understandable.

    Tool Count2/5

    39 tools is too many for a coherent agent-facing surface, even for a feature flag platform with many domains. The tools cover real functionality, but the count is high enough that discovery and selection are likely to be burdensome.

    Completeness4/5

    The surface broadly covers the feature flag lifecycle: flags, environments, targeting, variations, segments, SDK keys, webhooks, triggers, analytics, and cleanup workflows. Minor gaps remain, such as project/environment deletion and org member listing for ownership, but most core workflows are supported.

    Maintenance

    ActivityActive
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      B
      maintenance
      Enables interaction with LaunchDarkly's feature flag platform through AI clients. Supports managing feature flags, AI configs, and their variations with operations like create, update, delete, and targeting configuration.
      72,236 npm
      27
      MIT
    • A
      license
      A
      quality
      D
      maintenance
      Enables AI assistants to manage Featureflow feature flags, including creating and updating features, controlling feature states across environments, and managing projects, environments, and targeting rules through natural language.
      22
      6 npm
      MIT
    • A
      license
      Not graded
      quality
      B
      maintenance
      Enables AI coding assistants like Cursor and Claude to manage DevCycle feature flags directly from the development environment.
      15,615 npm
      20
      MIT