Repository navigation
Releases: canopy-labs/featureflip-mcp
Releases · canopy-labs/featureflip-mcp
Release list
v0.7.0
Added
- Critical environments.
manage_environmenttakesrequire_change_reasonandrequire_confirmationon create and update (omit either on update to leave it unchanged), andlist_environmentsreturns both. An environment withrequire_change_reasonneeds a reason on every write to it. The write tools take an optionalreason, sent asX-Intent-Reasonand recorded in the audit log:manage_environment,toggle_flag,update_flag_environment_config,update_targeting,manage_targeting_rule,manage_segment,manage_variation,delete_flag,archive_flagandrestore_flag. A write the API refuses withchange_reason_requirednow tells the agent to retry withreason. Needs the API's critical environments (#4639). (#4994) update_flagandmanage_sdk_keytakereasontoo. The API requires one when aclientSideVisiblechange touches a project with a critical environment, and when revoking a critical environment's SDK key (#4999, #5000). (#5028)manage_webhooktakesprovider: "Datadog"(Events API change events) orprovider: "Grafana"(annotations) on create. Both need a write-onlycredential, a Datadog API key or a Grafana service account token, which is stored encrypted and never returned. On update, omitcredentialto keep the stored one; changing theurlof a Datadog or Grafana subscription needs it again.rotate_secretis refused on these subscriptions, which authenticate with the credential instead. Needs the API's Datadog and Grafana destinations (#4650). (#4979)
Changed
- Turning a critical setting off through
manage_environmentneeds an Admin or Owner token as well as areason(#4998). (#5028)
v0.6.0
Added
manage_webhooktakes an optionalprovideron create:GenericHttp(the default) orSlack, so an agent can send flag changes to a Slack channel. Needs the API's Slack destination (#4649). (#4664)
Changed
manage_webhookrefuses a Slack incoming webhook URL (https://hooks.slack.com/services/...) on aGenericHttpsubscription, at create or update. Slack rejects the generic JSON payload, so that subscription would fail every delivery until auto-disable paused it. It also refusesprovideron any action except create, because a subscription's provider can't change, and refusesrotate_secreton a Slack subscription, whose signing secret is never used. (#4664)
v0.5.0
Added
manage_targeting_ruleandupdate_targetingtake an optionalbucketByon a rule: the context attribute its percentage rollout hashes on, such asanonymous_idoraccountId. It defaults touser_id. A visitor whose context lacks the attribute skips the rule, even at 100%. Amanage_targeting_ruleupdate that leaves it out keeps the rule's current value, except that a fixed rule has none: one made a rollout that way getsuser_id(#4607).flag_evaluationsnow returnsrollout.bucketBy, androllout.unreachedwhen a live rollout rule got no evaluations while 100 or more reached the flag's rules. (#4224)
v0.4.0
Added
flag_evaluationsreports what a flag served in one environment over the last 7, 30 or 90 days. It returns the total evaluations, the split by variation, and which rule (or the fallthrough, off, a prerequisite or an error) served what. A percentage-rollout rule also returns its configured weights and a sample-ratio check, androllout.flaggedis true when the served split is statistically off them. These are evaluation counts, not unique users. Zero means no SDK reported an evaluation, not necessarily that there was no traffic. Needs the API's newGET .../flags/{flag}/environments/{env}/evaluations. (#4225)
v0.3.0
Added
update_flag,update_targetingand amanage_segmentupdate now return theetagof what they wrote, taken from the write's own response. An agent can pass it asifMatchon its next write without reading the resource again. Before this, a second conditional write needed a fresh read first, or it failed with a 412. The ETag is never fetched with a follow-up read, which could pick up someone else's later write. When the API sends no ETag, the field is left out. (#3842)
Fixed
- A
manage_targeting_ruleupdate that leaves outconditionGroupsno longer fails with aTypeErrorwhen one of the rule's current groups hasconditions: null. The API contract allows null there. The group is now carried over with an empty list. (#3842)
v0.2.0
Added
set_default_flag_lifetimesets or removes a project's default flag lifetime.preview: truereports how many flags would newly be, or stop being, past expiry, without changing anything. (#3794)list_sdk_keysandmanage_sdk_key(create, rename, revoke). Creating a key returns the full key once, so an agent setting up an SDK can write it into an.envfile. The list shows only the last four characters.manage_segment(create, update, delete).update_targetingcould already reference a segment that nothing in the MCP server could create. A segment created withoutconditionsis sent with an empty list, which the API requires.manage_projectandmanage_environment(create, update). Neither can delete.manage_targeting_ruleadds, updates, removes or reorders one rule without replacing the whole list. A rule added here or throughupdate_targetingwithoutconditionGroups(segment-only or rollout-only) is sent with an empty list, which the API requires.- Optimistic concurrency.
get_flag,get_targetingandget_segmentreturn anetag, andupdate_flag,update_targetingand amanage_segmentupdate take it back asifMatch.manage_segmentrefusesifMatchon create and delete, which the API can't make conditional, instead of dropping it and writing unconditionally. (#3808) The write then fails with a 412 if the resource changed after the agent read it, instead of overwriting the other change. Tools that read before writing (update_flag,manage_webhook,manage_segment,manage_environment,manage_targeting_rule) also send the ETag from their own read.
Changed
- A write carrying If-Match is no longer retried after a 502 or 504. If the first attempt landed, the retry would fail with a 412 and blame someone else for the agent's own change. A 503 is still retried.
- An
ifMatchpassed without its surrounding quotes (abcinstead of"abc") is quoted before it is sent. Otherwise every conditional write would fail with a 412 that looks like a concurrent change.
v0.1.13
Added
- Every tool declares an
outputSchemaand returnsstructuredContentalongside the JSON text. Clients can type-check a result instead of parsing prose. Tools that pass an API response through take their schema from the public API spec, so it matches the API contract. The schema allows extra fields and nulls, so a field the API adds later can't make an older server version fail a call. find_stale_flagscounts a project's default flag lifetime. Each result now carrieseffectiveExpiresAtUtc, the date in effect from the flag or its project's default, andexpirySource(explicit,project-default, ornull). A flag with no date of its own can still be reported as past expiry. Against an API that doesn't report project defaults yet,effectiveExpiresAtUtcfalls back to the flag's own date. (#3194)
Changed
- Every tool parameter now has a description. 54 of 113 had only a name and a type, mostly
project,flag,environment,limitandcursor, along with fields likecreate_flag'stypeandupdate_targeting'srules. Agents now see what each parameter expects.
v0.1.12
Added
- Each release now carries
featureflip-mcp-<version>.mcpb, an MCP Bundle with the server and its dependencies inside. Claude Desktop installs it in one click and asks for the API token in its own settings, so there is no JSON config to write. Needs Node.js 20.19 or later. (#2588)
v0.1.11
Added
set_flag_permanentmarks a flag permanent, for a kill switch or ops toggle that is meant to stay, or makes it temporary again withpermanent: false.create_flagtakes an optionalisPermanentas well. Permanent flags are left out offind_stale_flagsandlist_removal_candidates. Marking is refused withPERMANENT_FLAG_HAS_EXPIRYwhile the flag has an expiry date, so clear the date first; making a flag temporary always works. (#3193, #3671)
Changed
set_flag_expirydocuments itsPERMANENT_FLAG_HAS_EXPIRYrefusal on a permanent flag.@modelcontextprotocol/server2.1.0 → 2.3.1.
v0.1.10
Added
list_removal_candidateslists the flags the server is confident can be removed from code, the same list the flag cleanup GitHub Action works from. Each item haskey,reason,status,treatment(which branch to keep) andblockedBy.stalenessisdead(the default) orstale. (#3458)find_stale_flagsreportsblockedByfor each flag: the live flags that still list it as a prerequisite and have to be removed and archived first. It is[]when nothing depends on the flag, andnullwhen the server didn't classify the flag as a removal candidate, which means unknown rather than unblocked. If the lookup fails, the stale report still comes back, with everyblockedByset tonulland ablockedByNotesaying why. Against an API that predatesblockedBy, every value isnull. (#3458)
Changed
find_stale_flags,list_removal_candidatesandarchive_flagtell the agent to remove dependents first.archive_flagrefuses a flag that another live flag still lists as a prerequisite (FLAG_HAS_DEPENDENTS), and the agent now hears that before trying.