@featureflip/mcp 0.1.9 → 0.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -3
- package/dist/cli.mjs +1 -1
- package/dist/generated/api-types.d.ts +209 -6
- package/dist/generated/api-types.d.ts.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{org-8tn1Su68.js → org-c4iWMSzU.js} +113 -63
- package/dist/tools/flags.d.ts.map +1 -1
- package/dist/tools/workflows/stale-flags.d.ts.map +1 -1
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -41,13 +41,14 @@ claude mcp add featureflip -e FEATUREFLIP_TOKEN=ffp_your_token -- npx -y @featur
|
|
|
41
41
|
## Tools
|
|
42
42
|
|
|
43
43
|
CRUD: `list_projects`, `list_environments`, `list_flags`, `get_flag`, `create_flag`, `update_flag`,
|
|
44
|
-
`delete_flag`, `archive_flag`, `restore_flag`, `set_flag_expiry`, `set_flag_owner`, `
|
|
45
|
-
`update_flag_environment_config`, `get_targeting`, `update_targeting`, `manage_variation`,
|
|
46
|
-
`get_segment`
|
|
44
|
+
`delete_flag`, `archive_flag`, `restore_flag`, `set_flag_expiry`, `set_flag_owner`, `set_flag_permanent`,
|
|
45
|
+
`toggle_flag`, `update_flag_environment_config`, `get_targeting`, `update_targeting`, `manage_variation`,
|
|
46
|
+
`list_segments`, `get_segment`
|
|
47
47
|
|
|
48
48
|
Webhooks (Admin token required): `list_webhooks`, `list_webhook_deliveries`, `manage_webhook`, `deliver_webhook`
|
|
49
49
|
|
|
50
50
|
Workflows: `flag_status` (cross-environment view), `find_stale_flags` (cleanup candidates),
|
|
51
|
+
`list_removal_candidates` (flags safe to remove, with the prerequisite dependents to remove first),
|
|
51
52
|
`wrap_feature` (create flag + get the SDK snippet for your language)
|
|
52
53
|
|
|
53
54
|
Full reference: https://featureflip.io/docs/integrations/mcp/
|
package/dist/cli.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as e, i as t, n, o as r, s as i, t as a } from "./org-
|
|
1
|
+
import { a as e, i as t, n, o as r, s as i, t as a } from "./org-c4iWMSzU.js";
|
|
2
2
|
import { serveStdio as o } from "@modelcontextprotocol/server/stdio";
|
|
3
3
|
//#region src/unconfigured.ts
|
|
4
4
|
var s = class extends i {
|
|
@@ -445,6 +445,7 @@ export interface paths {
|
|
|
445
445
|
* Decode's "garbage input degrades gracefully" precedent)
|
|
446
446
|
* rather than a 400, since it's a non-critical list filter, not a mutation. `owner` filters
|
|
447
447
|
* by owner: an email (an active member, case-insensitive) or `none` for unowned flags.
|
|
448
|
+
* `permanent` filters to permanent (`true`) or temporary (`false`) flags.
|
|
448
449
|
*/
|
|
449
450
|
get: {
|
|
450
451
|
parameters: {
|
|
@@ -456,6 +457,7 @@ export interface paths {
|
|
|
456
457
|
limit?: number;
|
|
457
458
|
cursor?: string;
|
|
458
459
|
owner?: string;
|
|
460
|
+
permanent?: boolean;
|
|
459
461
|
};
|
|
460
462
|
header?: never;
|
|
461
463
|
path: {
|
|
@@ -637,9 +639,13 @@ export interface paths {
|
|
|
637
639
|
/**
|
|
638
640
|
* Lists confidently-dead (or, with `staleness=stale`, stale-or-dead) flags the Featureflip Flag Cleanup Action should remove, cursor-paginated, each with its kill `treatment` (true = keep the on-branch, false = keep the off-branch).
|
|
639
641
|
* @description Only flags the staleness engine marks at or
|
|
640
|
-
* above the requested tier
|
|
641
|
-
* ZeroTraffic/CreatedUnused
|
|
642
|
-
*
|
|
642
|
+
* above the requested tier with a settled value are returned: a decisive StuckRolledOut/StuckRolledBack
|
|
643
|
+
* reason, or ZeroTraffic/CreatedUnused when no environment saw traffic and every environment's
|
|
644
|
+
* configuration serves one fixed variation (enabled, no rules, no prerequisites). Cross-env-divergent
|
|
645
|
+
* flags, flags without traffic whose configuration could serve more than one value, and archived
|
|
646
|
+
* flags are omitted (no confident code treatment). The ONLY public projection of staleness.
|
|
647
|
+
* Each item's `blockedBy` names the live flags that still list it as a prerequisite; while
|
|
648
|
+
* it is non-empty the flag cannot be archived (`FLAG_HAS_DEPENDENTS`), so remove those first.
|
|
643
649
|
*/
|
|
644
650
|
get: {
|
|
645
651
|
parameters: {
|
|
@@ -997,7 +1003,8 @@ export interface paths {
|
|
|
997
1003
|
* date (`2026-12-01`), which means the end of that day in UTC, the same as picking it in the
|
|
998
1004
|
* dashboard, or a full ISO-8601 timestamp, which is stored exactly. It must be in the future
|
|
999
1005
|
* (400 `EXPIRY_IN_PAST`), so today's date is accepted, and the flag-expiration feature must
|
|
1000
|
-
* be enabled (400 `FEATURE_NOT_ENABLED`).
|
|
1006
|
+
* be enabled (400 `FEATURE_NOT_ENABLED`). A permanent flag can't have a date
|
|
1007
|
+
* (400 `PERMANENT_FLAG_HAS_EXPIRY`).
|
|
1001
1008
|
*/
|
|
1002
1009
|
put: {
|
|
1003
1010
|
parameters: {
|
|
@@ -1371,6 +1378,193 @@ export interface paths {
|
|
|
1371
1378
|
patch?: never;
|
|
1372
1379
|
trace?: never;
|
|
1373
1380
|
};
|
|
1381
|
+
"/api/v1/orgs/{org}/projects/{project}/flags/{flag}/permanent": {
|
|
1382
|
+
parameters: {
|
|
1383
|
+
query?: never;
|
|
1384
|
+
header?: never;
|
|
1385
|
+
path?: never;
|
|
1386
|
+
cookie?: never;
|
|
1387
|
+
};
|
|
1388
|
+
get?: never;
|
|
1389
|
+
/**
|
|
1390
|
+
* Marks the flag permanent: a kill switch, ops toggle or entitlement gate that is meant to stay.
|
|
1391
|
+
* @description A permanent flag is never offered as a removal candidate and never reported past expiry.
|
|
1392
|
+
* Requires at least Member. The flag can't have an expiry date (400 `PERMANENT_FLAG_HAS_EXPIRY`;
|
|
1393
|
+
* remove the date first) and the flag-permanence feature must be enabled (400 `FEATURE_NOT_ENABLED`).
|
|
1394
|
+
*/
|
|
1395
|
+
put: {
|
|
1396
|
+
parameters: {
|
|
1397
|
+
query?: never;
|
|
1398
|
+
header?: never;
|
|
1399
|
+
path: {
|
|
1400
|
+
org: string;
|
|
1401
|
+
project: string;
|
|
1402
|
+
flag: string;
|
|
1403
|
+
};
|
|
1404
|
+
cookie?: never;
|
|
1405
|
+
};
|
|
1406
|
+
requestBody?: never;
|
|
1407
|
+
responses: {
|
|
1408
|
+
/** @description No Content */
|
|
1409
|
+
204: {
|
|
1410
|
+
headers: {
|
|
1411
|
+
"X-RateLimit-Limit": components["headers"]["X-RateLimit-Limit"];
|
|
1412
|
+
"X-RateLimit-Remaining": components["headers"]["X-RateLimit-Remaining"];
|
|
1413
|
+
"X-RateLimit-Reset": components["headers"]["X-RateLimit-Reset"];
|
|
1414
|
+
[name: string]: unknown;
|
|
1415
|
+
};
|
|
1416
|
+
content?: never;
|
|
1417
|
+
};
|
|
1418
|
+
/** @description Bad Request */
|
|
1419
|
+
400: {
|
|
1420
|
+
headers: {
|
|
1421
|
+
"X-RateLimit-Limit": components["headers"]["X-RateLimit-Limit"];
|
|
1422
|
+
"X-RateLimit-Remaining": components["headers"]["X-RateLimit-Remaining"];
|
|
1423
|
+
"X-RateLimit-Reset": components["headers"]["X-RateLimit-Reset"];
|
|
1424
|
+
[name: string]: unknown;
|
|
1425
|
+
};
|
|
1426
|
+
content: {
|
|
1427
|
+
"application/json": components["schemas"]["PublicApiErrorEnvelope"];
|
|
1428
|
+
};
|
|
1429
|
+
};
|
|
1430
|
+
/** @description Authentication is required, or the supplied API token is invalid or expired. */
|
|
1431
|
+
401: {
|
|
1432
|
+
headers: {
|
|
1433
|
+
"X-RateLimit-Limit": components["headers"]["X-RateLimit-Limit"];
|
|
1434
|
+
"X-RateLimit-Remaining": components["headers"]["X-RateLimit-Remaining"];
|
|
1435
|
+
"X-RateLimit-Reset": components["headers"]["X-RateLimit-Reset"];
|
|
1436
|
+
[name: string]: unknown;
|
|
1437
|
+
};
|
|
1438
|
+
content: {
|
|
1439
|
+
"application/json": components["schemas"]["PublicApiErrorEnvelope"];
|
|
1440
|
+
};
|
|
1441
|
+
};
|
|
1442
|
+
/** @description Forbidden */
|
|
1443
|
+
403: {
|
|
1444
|
+
headers: {
|
|
1445
|
+
"X-RateLimit-Limit": components["headers"]["X-RateLimit-Limit"];
|
|
1446
|
+
"X-RateLimit-Remaining": components["headers"]["X-RateLimit-Remaining"];
|
|
1447
|
+
"X-RateLimit-Reset": components["headers"]["X-RateLimit-Reset"];
|
|
1448
|
+
[name: string]: unknown;
|
|
1449
|
+
};
|
|
1450
|
+
content: {
|
|
1451
|
+
"application/json": components["schemas"]["PublicApiErrorEnvelope"];
|
|
1452
|
+
};
|
|
1453
|
+
};
|
|
1454
|
+
/** @description Not Found */
|
|
1455
|
+
404: {
|
|
1456
|
+
headers: {
|
|
1457
|
+
"X-RateLimit-Limit": components["headers"]["X-RateLimit-Limit"];
|
|
1458
|
+
"X-RateLimit-Remaining": components["headers"]["X-RateLimit-Remaining"];
|
|
1459
|
+
"X-RateLimit-Reset": components["headers"]["X-RateLimit-Reset"];
|
|
1460
|
+
[name: string]: unknown;
|
|
1461
|
+
};
|
|
1462
|
+
content: {
|
|
1463
|
+
"application/json": components["schemas"]["PublicApiErrorEnvelope"];
|
|
1464
|
+
};
|
|
1465
|
+
};
|
|
1466
|
+
/** @description Rate limit exceeded. Retry after the interval indicated by the Retry-After header. */
|
|
1467
|
+
429: {
|
|
1468
|
+
headers: {
|
|
1469
|
+
/** @description Number of seconds to wait before retrying the request. */
|
|
1470
|
+
"Retry-After"?: number;
|
|
1471
|
+
"X-RateLimit-Limit": components["headers"]["X-RateLimit-Limit"];
|
|
1472
|
+
"X-RateLimit-Remaining": components["headers"]["X-RateLimit-Remaining"];
|
|
1473
|
+
"X-RateLimit-Reset": components["headers"]["X-RateLimit-Reset"];
|
|
1474
|
+
[name: string]: unknown;
|
|
1475
|
+
};
|
|
1476
|
+
content: {
|
|
1477
|
+
"application/json": components["schemas"]["PublicApiErrorEnvelope"];
|
|
1478
|
+
};
|
|
1479
|
+
};
|
|
1480
|
+
};
|
|
1481
|
+
};
|
|
1482
|
+
post?: never;
|
|
1483
|
+
/**
|
|
1484
|
+
* Makes the flag temporary again.
|
|
1485
|
+
* @description Requires at least Member. Always allowed, even when the
|
|
1486
|
+
* flag-permanence feature is disabled.
|
|
1487
|
+
*/
|
|
1488
|
+
delete: {
|
|
1489
|
+
parameters: {
|
|
1490
|
+
query?: never;
|
|
1491
|
+
header?: never;
|
|
1492
|
+
path: {
|
|
1493
|
+
org: string;
|
|
1494
|
+
project: string;
|
|
1495
|
+
flag: string;
|
|
1496
|
+
};
|
|
1497
|
+
cookie?: never;
|
|
1498
|
+
};
|
|
1499
|
+
requestBody?: never;
|
|
1500
|
+
responses: {
|
|
1501
|
+
/** @description No Content */
|
|
1502
|
+
204: {
|
|
1503
|
+
headers: {
|
|
1504
|
+
"X-RateLimit-Limit": components["headers"]["X-RateLimit-Limit"];
|
|
1505
|
+
"X-RateLimit-Remaining": components["headers"]["X-RateLimit-Remaining"];
|
|
1506
|
+
"X-RateLimit-Reset": components["headers"]["X-RateLimit-Reset"];
|
|
1507
|
+
[name: string]: unknown;
|
|
1508
|
+
};
|
|
1509
|
+
content?: never;
|
|
1510
|
+
};
|
|
1511
|
+
/** @description Authentication is required, or the supplied API token is invalid or expired. */
|
|
1512
|
+
401: {
|
|
1513
|
+
headers: {
|
|
1514
|
+
"X-RateLimit-Limit": components["headers"]["X-RateLimit-Limit"];
|
|
1515
|
+
"X-RateLimit-Remaining": components["headers"]["X-RateLimit-Remaining"];
|
|
1516
|
+
"X-RateLimit-Reset": components["headers"]["X-RateLimit-Reset"];
|
|
1517
|
+
[name: string]: unknown;
|
|
1518
|
+
};
|
|
1519
|
+
content: {
|
|
1520
|
+
"application/json": components["schemas"]["PublicApiErrorEnvelope"];
|
|
1521
|
+
};
|
|
1522
|
+
};
|
|
1523
|
+
/** @description Forbidden */
|
|
1524
|
+
403: {
|
|
1525
|
+
headers: {
|
|
1526
|
+
"X-RateLimit-Limit": components["headers"]["X-RateLimit-Limit"];
|
|
1527
|
+
"X-RateLimit-Remaining": components["headers"]["X-RateLimit-Remaining"];
|
|
1528
|
+
"X-RateLimit-Reset": components["headers"]["X-RateLimit-Reset"];
|
|
1529
|
+
[name: string]: unknown;
|
|
1530
|
+
};
|
|
1531
|
+
content: {
|
|
1532
|
+
"application/json": components["schemas"]["PublicApiErrorEnvelope"];
|
|
1533
|
+
};
|
|
1534
|
+
};
|
|
1535
|
+
/** @description Not Found */
|
|
1536
|
+
404: {
|
|
1537
|
+
headers: {
|
|
1538
|
+
"X-RateLimit-Limit": components["headers"]["X-RateLimit-Limit"];
|
|
1539
|
+
"X-RateLimit-Remaining": components["headers"]["X-RateLimit-Remaining"];
|
|
1540
|
+
"X-RateLimit-Reset": components["headers"]["X-RateLimit-Reset"];
|
|
1541
|
+
[name: string]: unknown;
|
|
1542
|
+
};
|
|
1543
|
+
content: {
|
|
1544
|
+
"application/json": components["schemas"]["PublicApiErrorEnvelope"];
|
|
1545
|
+
};
|
|
1546
|
+
};
|
|
1547
|
+
/** @description Rate limit exceeded. Retry after the interval indicated by the Retry-After header. */
|
|
1548
|
+
429: {
|
|
1549
|
+
headers: {
|
|
1550
|
+
/** @description Number of seconds to wait before retrying the request. */
|
|
1551
|
+
"Retry-After"?: number;
|
|
1552
|
+
"X-RateLimit-Limit": components["headers"]["X-RateLimit-Limit"];
|
|
1553
|
+
"X-RateLimit-Remaining": components["headers"]["X-RateLimit-Remaining"];
|
|
1554
|
+
"X-RateLimit-Reset": components["headers"]["X-RateLimit-Reset"];
|
|
1555
|
+
[name: string]: unknown;
|
|
1556
|
+
};
|
|
1557
|
+
content: {
|
|
1558
|
+
"application/json": components["schemas"]["PublicApiErrorEnvelope"];
|
|
1559
|
+
};
|
|
1560
|
+
};
|
|
1561
|
+
};
|
|
1562
|
+
};
|
|
1563
|
+
options?: never;
|
|
1564
|
+
head?: never;
|
|
1565
|
+
patch?: never;
|
|
1566
|
+
trace?: never;
|
|
1567
|
+
};
|
|
1374
1568
|
"/api/v1/orgs/{org}/projects/{project}/flags/{flag}/removal-pr": {
|
|
1375
1569
|
parameters: {
|
|
1376
1570
|
query?: never;
|
|
@@ -5960,7 +6154,10 @@ export interface components {
|
|
|
5960
6154
|
* (400 `EXPIRY_IN_PAST` / `FEATURE_NOT_ENABLED`). OwnerEmail optionally names
|
|
5961
6155
|
* the owner (an active member, matched case-insensitively; requires the flag-ownership feature —
|
|
5962
6156
|
* 400 `OWNER_NOT_MEMBER` / `FEATURE_NOT_ENABLED`). Omitted, the owner is the caller when
|
|
5963
|
-
* the caller is a member, so a service token creates an unowned flag.
|
|
6157
|
+
* the caller is a member, so a service token creates an unowned flag. IsPermanent marks
|
|
6158
|
+
* the flag permanent (a kill switch, ops toggle or entitlement that is meant to stay; never reported for
|
|
6159
|
+
* cleanup). It requires the flag-permanence feature and can't be combined with ExpiresAtUtc
|
|
6160
|
+
* (400 `FEATURE_NOT_ENABLED` / `PERMANENT_FLAG_HAS_EXPIRY`).
|
|
5964
6161
|
* @example {
|
|
5965
6162
|
* "key": "new-checkout-flow",
|
|
5966
6163
|
* "name": "New Checkout Flow",
|
|
@@ -6002,6 +6199,7 @@ export interface components {
|
|
|
6002
6199
|
/** Format: date-time */
|
|
6003
6200
|
expiresAtUtc?: string | null;
|
|
6004
6201
|
ownerEmail?: string | null;
|
|
6202
|
+
isPermanent?: boolean;
|
|
6005
6203
|
};
|
|
6006
6204
|
/**
|
|
6007
6205
|
* @description Request body for `POST /api/v1/orgs/{org}/projects`. Named distinctly from the
|
|
@@ -6312,6 +6510,7 @@ export interface components {
|
|
|
6312
6510
|
expiresAtUtc?: string | null;
|
|
6313
6511
|
owner?: components["schemas"]["PublicFlagOwner"];
|
|
6314
6512
|
removalPrUrl?: string | null;
|
|
6513
|
+
isPermanent?: boolean;
|
|
6315
6514
|
};
|
|
6316
6515
|
/**
|
|
6317
6516
|
* @description A page of results plus an opaque cursor for the next page, or null when this is the last
|
|
@@ -6359,13 +6558,16 @@ export interface components {
|
|
|
6359
6558
|
* (`"Stale"` or `"Dead"`, never `"Active"`) — lets a caller distinguish the two when
|
|
6360
6559
|
* `?staleness=stale` widens the response to include both tiers. This is the ONLY public
|
|
6361
6560
|
* projection of staleness — PublicFlagResponse and PublicFlagListItem
|
|
6362
|
-
* still omit it by design.
|
|
6561
|
+
* still omit it by design. `BlockedBy` names the live flags that still list this one as a
|
|
6562
|
+
* prerequisite, sorted by key; while it is non-empty the flag cannot be archived
|
|
6563
|
+
* (`FLAG_HAS_DEPENDENTS`), so a caller should remove those dependents first.
|
|
6363
6564
|
*/
|
|
6364
6565
|
PublicFlagRemovalCandidate: {
|
|
6365
6566
|
key?: string | null;
|
|
6366
6567
|
reason?: string | null;
|
|
6367
6568
|
treatment?: boolean;
|
|
6368
6569
|
status?: string | null;
|
|
6570
|
+
blockedBy?: string[] | null;
|
|
6369
6571
|
};
|
|
6370
6572
|
/**
|
|
6371
6573
|
* @description A page of results plus an opaque cursor for the next page, or null when this is the last
|
|
@@ -6436,6 +6638,7 @@ export interface components {
|
|
|
6436
6638
|
expiresAtUtc?: string | null;
|
|
6437
6639
|
owner?: components["schemas"]["PublicFlagOwner"];
|
|
6438
6640
|
removalPrUrl?: string | null;
|
|
6641
|
+
isPermanent?: boolean;
|
|
6439
6642
|
/** @description Capability hints: which operations the authenticated caller may perform on this resource, each with allowed + optional reason. Computed from the caller's role and the resource's state. Injected at runtime; safe to ignore. Present only on top-level resource responses — nested occurrences (e.g. a rule inside a targeting-config response) do not carry it. */
|
|
6440
6643
|
_actions?: {
|
|
6441
6644
|
[key: string]: components["schemas"]["ActionCapability"];
|